2015-01-17 22 views
6

Thành thật mà nói, tôi không ngạc nhiên khi chưa có ai chạy vào điều này. Tôi đang tải một hình ảnh từ OpenCV vào cv :: Mat, mà tôi muốn mã hóa base64 trước khi tôi gửi nó qua một ổ cắm.OpenCV cv :: Mat to std :: ifstream cho mã hóa base64

Đối với base64 tôi đang sử dụng libb64 vì nó có nguồn gốc Debian/Ubuntu và dễ sử dụng và rất nhanh. Hàm mã hóa lấy tham số là std :: ifstream và xuất kết quả là std :: của dòng.

#include <opencv2/opencv.hpp> 
#include <b64/encode.h> 
#include <fstream> 

using namespace cv; 
Mat image; 
image = imread("picture.jpg", CV_LOAD_IMAGE_COLOR); 

if (image.data) 
{ 
    std::ifstream instream(???, std::ios_base::in | std::ios_base::binary); 
    std::ofstream outstream;   

    // Convert Matrix to ifstream 
    // ... 

    base64::encoder E; 
    E.encode(instream, outstream); 

    // Now put it in a string, and send it over a socket... 
} 

Tôi thực sự không biết cách điền trực tiếp từ cv :: Mat. Googling xung quanh, tôi thấy rằng tôi có thể lặp một cv :: Mat, bởi các cột và các hàng, và nhận được mỗi (pixel Tôi giả định) giá trị RGB:

for (int j = 0; j < image.rows; j++) 
{ 
    for (int i = 0; i < image.cols; i++) 
    { 
     unsigned char b = input [ image.step * j + i ] ; 
     unsigned char g = input [ image.step * j + i + 1 ]; 
     unsigned char r = input [ image.step * j + i + 2 ]; 
    } 
} 

Đây có phải là một cách đúng đắn của xảy ra về nó ? Có cách nào thanh lịch hơn không?

+0

Bạn đang cố gắng hoàn thành những gì cuối cùng? Bạn có muốn tuần tự hóa hình ảnh (bạn có muốn đọc nó ở phía bên kia) không? Nếu bạn chỉ mã hóa dữ liệu hình ảnh, thì bạn sẽ không biết chiều rộng, chiều cao hoặc số kênh của nó. Tại sao bạn không base64 mã hóa các tập tin đầu vào thay vì Mat? Ngoài ra, nếu bạn muốn gửi hình ảnh trên một ổ cắm, bạn không thực sự cần phải mã hóa base64, bạn chỉ có thể gửi nó như là và giảm chi phí. – Ove

+0

@Ove đầu kia trên ổ cắm có thể là kiến ​​trúc hoặc nền tảng khác nhau và sẽ không sử dụng C++. Tôi đã hy vọng tôi sẽ tránh những vấn đề nhất định bằng cách serialising với base64, nhưng tôi mở cho bất kỳ đề xuất. Vì vậy, bạn nghĩ rằng nó chỉ tốt hơn để serialise hình ảnh thay vì cv :: Mat? Vấn đề là, có thể không có bất kỳ hình ảnh nào, nhưng một hình ảnh được chụp bằng máy ảnh. Ngoài ra, socket đang sử dụng giao thức HTTP, vì vậy tôi đang đăng văn bản JSON. –

Trả lời

7

Để có thể gửi hình ảnh qua HTTP, bạn cũng cần phải mã hóa chiều rộng, chiều cao và loại của nó. Bạn cần phải tuần tự hóa Mat vào luồng và mã hóa luồng đó bằng libb64. Ở phía bên kia, bạn cần phải giải mã luồng đó và deserialize hình ảnh để lấy nó.

Tôi đã triển khai một chương trình thử nghiệm nhỏ thực hiện việc tuần tự hóa và deserialization này bằng cách sử dụng std::stringstream làm bộ đệm. Tôi đã chọn nó vì nó mở rộng cả hai std::istreamstd::ostream mà libb64 sử dụng.

Chức năng serialize tuần tự hóa cv::Mat thành std::stringstream. Trong đó, tôi viết chiều rộng hình ảnh, chiều cao, loại, kích thước của bộ đệm và chính bộ đệm.

Chức năng deserialize làm ngược lại. Nó đọc chiều rộng, chiều cao, loại, kích thước của bộ đệm và bộ đệm. Nó không hiệu quả vì nó có thể là do nó cần phân bổ một bộ đệm tạm thời để đọc dữ liệu từ chuỗi. Ngoài ra, nó cần phải sao chép các hình ảnh để nó không dựa vào bộ đệm tạm thời và nó sẽ xử lý phân bổ bộ nhớ riêng của nó. Tôi chắc chắn rằng với một số tinkering nó có thể được thực hiện hiệu quả hơn.

Chức năng chính tải hình ảnh, tuần tự hóa nó, mã hóa nó bằng cách sử dụng libb64, sau đó giải mã nó, deserializes nó và hiển thị nó trong một cửa sổ. Điều này sẽ mô phỏng những gì bạn đang cố gắng làm.

// Serialize a cv::Mat to a stringstream 
stringstream serialize(Mat input) 
{ 
    // We will need to also serialize the width, height, type and size of the matrix 
    int width = input.cols; 
    int height = input.rows; 
    int type = input.type(); 
    size_t size = input.total() * input.elemSize(); 

    // Initialize a stringstream and write the data 
    stringstream ss; 
    ss.write((char*)(&width), sizeof(int)); 
    ss.write((char*)(&height), sizeof(int)); 
    ss.write((char*)(&type), sizeof(int)); 
    ss.write((char*)(&size), sizeof(size_t)); 

    // Write the whole image data 
    ss.write((char*)input.data, size); 

    return ss; 
} 

// Deserialize a Mat from a stringstream 
Mat deserialize(stringstream& input) 
{ 
    // The data we need to deserialize 
    int width = 0; 
    int height = 0; 
    int type = 0; 
    size_t size = 0; 

    // Read the width, height, type and size of the buffer 
    input.read((char*)(&width), sizeof(int)); 
    input.read((char*)(&height), sizeof(int)); 
    input.read((char*)(&type), sizeof(int)); 
    input.read((char*)(&size), sizeof(size_t)); 

    // Allocate a buffer for the pixels 
    char* data = new char[size]; 
    // Read the pixels from the stringstream 
    input.read(data, size); 

    // Construct the image (clone it so that it won't need our buffer anymore) 
    Mat m = Mat(height, width, type, data).clone(); 

    // Delete our buffer 
    delete[]data; 

    // Return the matrix 
    return m; 
} 

void main() 
{ 
    // Read a test image 
    Mat input = imread("D:\\test\\test.jpg"); 

    // Serialize the input image to a stringstream 
    stringstream serializedStream = serialize(input); 

    // Base64 encode the stringstream 
    base64::encoder E; 
    stringstream encoded; 
    E.encode(serializedStream, encoded); 

    // Base64 decode the stringstream 
    base64::decoder D; 
    stringstream decoded; 
    D.decode(encoded, decoded); 

    // Deserialize the image from the decoded stringstream 
    Mat deserialized = deserialize(decoded); 

    // Show the retrieved image 
    imshow("Retrieved image", deserialized); 
    waitKey(0); 
} 
+0

Wow, cảm ơn bạn rất nhiều! Tôi đã không mong đợi để được cho ăn muỗng câu trả lời :-) –

+0

Mã này có vẻ đã lỗi thời, sử dụng các tiện ích chuỗi đã bị xóa –

Các vấn đề liên quan