您的位置:

详解cv::imdecode函数

图像处理一直是计算机视觉中的一个重要领域,opencv作为开源的计算机视觉库,实现了很多经典的图像处理算法。其中,cv::imdecode函数是非常重要的一个函数,它能够将存储在内存中的图像解码成opencv的Mat数据类型。这篇文章将从不同的角度对这个函数进行详细的讲解。

一、使用cv::imdecode函数读取图片文件

cv::imdecode函数最常见的用法是读取图片文件。它可以将图片文件读取到内存中,并将其解码为opencv的Mat格式。

#include "opencv2/highgui/highgui.hpp"
#include "opencv2/imgproc/imgproc.hpp"
#include 
#include 
   

using namespace std;
using namespace cv;

int main()
{
    string img_path = "test.png";
    vector<uchar> img_data;
    Mat img;

    // 读取图片文件到内存中
    ifstream in(img_path, std::ios::binary);
    in.unsetf(std::ios::skipws); // 不跳过空白字符
    streampos file_size;
    in.seekg(0, ios::end);
    file_size = in.tellg();
    in.seekg(0, ios::beg);
    img_data.reserve(file_size);
    img_data.insert(img_data.begin(),
                    istream_iterator<uchar>(in),
                    istream_iterator<uchar>());
    in.close();

    // 解码图片并显示
    img = imdecode(img_data, CV_LOAD_IMAGE_COLOR);
    imshow("Image", img);
    waitKey(0);

    return 0;
}

   
  

上述代码中,我们首先读取了一张图片文件到内存中,然后将其解码为opencv的Mat格式,并使用imshow函数显示图片。这是最常见的使用cv::imdecode函数的方式,它对于读取网络上的图片等场景非常方便。

二、使用cv::imdecode函数解码编码过的图像

有一些场景下,图像在传输过程中可能会进行编码。比如,JPEG图像和PNG图像就是经过编码的。在这种情况下,我们可以使用cv::imdecode函数将编码后的图像解码为opencv的Mat格式。

#include "opencv2/highgui/highgui.hpp"
#include "opencv2/imgproc/imgproc.hpp"
#include 
#include 
   

using namespace std;
using namespace cv;

int main()
{
    string img_path = "test.jpg";
    vector<uchar> img_data;
    Mat img1, img2;

    // 读取JPEG图片文件到内存中
    ifstream in(img_path, std::ios::binary);
    in.unsetf(std::ios::skipws); // 不跳过空白字符
    streampos file_size;
    in.seekg(0, ios::end);
    file_size = in.tellg();
    in.seekg(0, ios::beg);
    img_data.reserve(file_size);
    img_data.insert(img_data.begin(),
                    istream_iterator<uchar>(in),
                    istream_iterator<uchar>());
    in.close();

    // 解码JPEG图片并显示
    img1 = imdecode(img_data, CV_LOAD_IMAGE_COLOR);
    imshow("JPEG Image", img1);

    // 编码图像
    vector<int> params; // JPEG参数
    params.push_back(CV_IMWRITE_JPEG_QUALITY); // JPEG质量
    params.push_back(60); // 图片质量,0~100
    imencode(".jpg", img1, img_data, params);

    // 解码编码后的JPEG图片并显示
    img2 = imdecode(img_data, CV_LOAD_IMAGE_COLOR);
    imshow("Encoded and Decoded JPEG Image", img2);
    waitKey(0);

    return 0;
}

   
  

上述代码中,我们首先读取了一张JPEG图片文件到内存中,然后将其解码为opencv的Mat格式并显示。接着,我们将图片编码为JPEG格式,将编码后的图片重新解码为opencv的Mat格式并显示。这种方式可以用于测试编码和解码算法。注意,这里需要将编码后的数据存储到vector<uchar>类型中,因为它是不定长的。

三、使用cv::imdecode函数解码从网络收到的图像

在一些应用场景下,我们需要从网络中接收图像,然后进行处理。这时,cv::imdecode函数也能够非常方便地解码从网络收到的图像。

#include "opencv2/highgui/highgui.hpp"
#include "opencv2/imgproc/imgproc.hpp"
#include 
#include 
   
#include 
    

#pragma comment(lib, "ws2_32.lib")

using namespace std;
using namespace cv;

int main()
{
    string server_ip = "127.0.0.1";
    int server_port = 8080;
    WSADATA wsaData;
    WSAStartup(MAKEWORD(2, 2), &wsaData);
    SOCKET sock = socket(AF_INET, SOCK_STREAM, 0);
    sockaddr_in server_addr;
    server_addr.sin_family = AF_INET;
    server_addr.sin_addr.s_addr = inet_addr(server_ip.c_str());
    server_addr.sin_port = htons(server_port);
    connect(sock, (sockaddr*)&server_addr, sizeof(server_addr));
    
    // 接收图像数据并解码成opencv的Mat格式
    vector<uchar> img_data;
    int img_size;
    recv(sock, (char*)&img_size, sizeof(img_size), 0);
    img_size = ntohl(img_size);
    img_data.resize(img_size);
    recv(sock, (char*)&img_data[0], img_size, 0);
    Mat img = imdecode(img_data, CV_LOAD_IMAGE_COLOR);

    imshow("Image", img);
    waitKey(0);

    closesocket(sock);
    WSACleanup();

    return 0;
}

    
   
  

上述代码中,我们首先通过socket从服务器接收一个图像数据包。接着,将数据包的长度和内容存储到img_size和img_data中,并使用cv::imdecode函数将其解码成opencv的Mat格式,最后使用imshow函数显示图片。

四、使用cv::imdecode函数解码指定格式图片

除了读取文件和解码编码过的图像以外,cv::imdecode函数还能够解码指定格式的图片。比如,如果我们要读取一张20通道的图像,就可以使用cv::imdecode函数解码。这种情况下,我们需要先将图像编码成一种通用格式,比如JPEG或PNG。

#include "opencv2/highgui/highgui.hpp"
#include "opencv2/imgproc/imgproc.hpp"
#include 
#include 
   
#include 
    

using namespace std;
using namespace cv;

int main()
{
    string img_path = "test.tif";
    vector<uchar> img_data;
    Mat img1, img2;

    // 读取20通道的图像文件到内存中
    ifstream in(img_path, std::ios::binary);
    in.unsetf(std::ios::skipws); // 不跳过空白字符
    streampos file_size;
    in.seekg(0, ios::end);
    file_size = in.tellg();
    in.seekg(0, ios::beg);
    img_data.reserve(file_size);
    img_data.insert(img_data.begin(),
                    istream_iterator<uchar>(in),
                    istream_iterator<uchar>());
    in.close();

    // 将20通道的图像编码为PNG格式
    vector<int> params; // PNG参数
    params.push_back(CV_IMWRITE_PNG_COMPRESSION); // PNG压缩程度
    params.push_back(3); // 压缩程度,0~9
    imencode(".png", Mat(100, 100, CV_8UC(20), Scalar(0)), img_data, params);

    // 解码PNG格式的图像并显示
    img1 = imdecode(img_data, CV_LOAD_IMAGE_UNCHANGED);
    imshow("20-channel Image", img1);

    // 将20通道的图像编码为JPEG格式
    params.clear(); // 清空参数
    params.push_back(CV_IMWRITE_JPEG_QUALITY); // JPEG质量
    params.push_back(60); // 图片质量,0~100
    imencode(".jpg", Mat(100, 100, CV_8UC(20), Scalar(0)), img_data, params);

    // 解码JPEG格式的图像并显示
    img2 = imdecode(img_data, CV_LOAD_IMAGE_UNCHANGED);
    imshow("20-channel Image Encoded and Decoded", img2);
    waitKey(0);

    return 0;
}

    
   
  

上述代码中,我们首先读取了一张20通道的图像文件到内存中。接着,我们将图像编码为PNG格式,并使用cv::imdecode函数将其解码为opencv的Mat格式。同样地,我们将图像编码为JPEG格式,并使用cv::imdecode函数将其解码为opencv的Mat格式。这种方式可以用于特殊的图像格式处理。