Opencv和Qt QImage格式转Mat

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Opencv和Qt QImage格式转Mat相关的知识,希望对你有一定的参考价值。

目的:在Qt creator中用QImage读取内存里的一张图片,转换成cv::Mat格式(或Iplimage格式)进行图像算法处理
我实验用本地磁盘里的一张24位或者8位图像,可以顺利从QImage转成Mat,但从内存读取的图像就不行。
读取本地图片代码如下:(8位图像,只用了一个通道) QImage image("E:/Test_Picture/ver.tif");
qDebug()<<image.format();
cv::Mat mat = cv::Mat(image.height(),image.width(),
CV_8UC1, (uchar*)image.bits(), image.bytesPerLine());
cv::Mat mat2 = cv::Mat(mat.rows, mat.cols, CV_8UC1 );
int from_to[] = 0,0,1,1,2,2;
cv::mixChannels(&mat,1,&mat2,1,from_to,1);
namedWindow("QImage2Mat");
imshow("QImage2Mat",mat2);读取本地图片代码(24位,QImage4个通道转成mat三个通道):
QImage image("D:/Picture/boy.jpg");
qDebug()<<image.format();
cv::Mat mat = cv::Mat(image.height(),image.width(),
CV_8UC4, (uchar*)image.bits(), image.bytesPerLine());
cv::Mat mat2 = cv::Mat(mat.rows, mat.cols, CV_8UC3 );
int from_to[] = 0,0,1,1,2,2;
cv::mixChannels(&mat,1,&mat2,1,from_to,3);
namedWindow("QImage2Mat");
imshow("QImage2Mat",mat2);这两个都成功了,但是当我读取相机采集到内存的图片时,无论QImage以什么格式保存都报错
代码如下: QImage image(aa->m_pRawBuffer,1000,700,QImage::Format_RGB888);
Mat mat =Mat(image.height(),image.width(),
CV_8UC3, (uchar*)image.bits(), image.bytesPerLine());
Mat mat2 =Mat(mat.rows, mat.cols, CV_8UC3 );
int from_to[] = 0,0,1,1,2,2;
mixChannels(&mat,1,&mat2,1,from_to,3);
namedWindow("test");
imshow("test",mat2);
按道理说都是三个通道不应该出错啊,问题出在了哪里呢?
第三段代码中如果QImage以Format_Index8格式读取的话,只拷贝第一个通道也是可以的,但是图片的结果是全部是蓝色,也就是Mat中B这个通道。求高手解答。

或者从内存中能不能直接用Mat格式或者Iplimage格式读取,这样我就不用QImage转Mat了。

参考技术A 整个项目的结构图:

编写DetectFaceDemo.java,代码如下:

[java] view
plaincopyprint?

package com.njupt.zhb.test;

import org.opencv.core.Core;

import org.opencv.core.Mat;

import org.opencv.core.MatOfRect;

import org.opencv.core.Point;

import org.opencv.core.Rect;

import org.opencv.core.Scalar;

import org.opencv.highgui.Highgui;

import org.opencv.objdetect.CascadeClassifier;

//

// Detects faces in an image, draws boxes around them, and writes the results

// to "faceDetection.png".

//

public class DetectFaceDemo

public void run()

System.out.println("\nRunning DetectFaceDemo");

System.out.println(getClass().getResource("lbpcascade_frontalface.xml").getPath());

// Create a face detector from the cascade file in the resources

// directory.

//CascadeClassifier faceDetector = new CascadeClassifier(getClass().getResource("lbpcascade_frontalface.xml").getPath());

//Mat image = Highgui.imread(getClass().getResource("lena.png").getPath());

//注意:源程序的路径会多打印一个‘/’,因此总是出现如下错误

/*

* Detected 0 faces Writing faceDetection.png libpng warning: Image

* width is zero in IHDR libpng warning: Image height is zero in IHDR

* libpng error: Invalid IHDR data

*/

//因此,我们将第一个字符去掉

String xmlfilePath=getClass().getResource("lbpcascade_frontalface.xml").getPath().substring(1);

CascadeClassifier faceDetector = new CascadeClassifier(xmlfilePath);

Mat image = Highgui.imread(getClass().getResource("we.jpg").getPath().substring(1));

// Detect faces in the image.

// MatOfRect is a special container class for Rect.

MatOfRect faceDetections = new MatOfRect();

faceDetector.detectMultiScale(image, faceDetections);

System.out.println(String.format("Detected %s faces", faceDetections.toArray().length));

// Draw a bounding box around each face.

for (Rect rect : faceDetections.toArray())

Core.rectangle(image, new Point(rect.x, rect.y), new Point(rect.x + rect.width, rect.y + rect.height), new Scalar(0, 255, 0));



// Save the visualized detection.

String filename = "faceDetection.png";

System.out.println(String.format("Writing %s", filename));

Highgui.imwrite(filename, image);




package com.njupt.zhb.test;
import org.opencv.core.Core;
import org.opencv.core.Mat;
import org.opencv.core.MatOfRect;
import org.opencv.core.Point;
import org.opencv.core.Rect;
import org.opencv.core.Scalar;
import org.opencv.highgui.Highgui;
import org.opencv.objdetect.CascadeClassifier;

//
// Detects faces in an image, draws boxes around them, and writes the results
// to "faceDetection.png".
//
public class DetectFaceDemo
public void run()
System.out.println("\nRunning DetectFaceDemo");
System.out.println(getClass().getResource("lbpcascade_frontalface.xml").getPath());
// Create a face detector from the cascade file in the resources
// directory.
//CascadeClassifier faceDetector = new CascadeClassifier(getClass().getResource("lbpcascade_frontalface.xml").getPath());
//Mat image = Highgui.imread(getClass().getResource("lena.png").getPath());
//注意:源程序的路径会多打印一个‘/’,因此总是出现如下错误
/*
* Detected 0 faces Writing faceDetection.png libpng warning: Image
* width is zero in IHDR libpng warning: Image height is zero in IHDR
* libpng error: Invalid IHDR data
*/
//因此,我们将第一个字符去掉
String xmlfilePath=getClass().getResource("lbpcascade_frontalface.xml").getPath().substring(1);
CascadeClassifier faceDetector = new CascadeClassifier(xmlfilePath);
Mat image = Highgui.imread(getClass().getResource("we.jpg").getPath().substring(1));
// Detect faces in the image.
// MatOfRect is a special container class for Rect.
MatOfRect faceDetections = new MatOfRect();
faceDetector.detectMultiScale(image, faceDetections);

System.out.println(String.format("Detected %s faces", faceDetections.toArray().length));

// Draw a bounding box around each face.
for (Rect rect : faceDetections.toArray())
Core.rectangle(image, new Point(rect.x, rect.y), new Point(rect.x + rect.width, rect.y + rect.height), new Scalar(0, 255, 0));


// Save the visualized detection.
String filename = "faceDetection.png";
System.out.println(String.format("Writing %s", filename));
Highgui.imwrite(filename, image);



3.编写测试类:

[java] view
plaincopyprint?

package com.njupt.zhb.test;

public class TestMain

public static void main(String[] args)

System.out.println("Hello, OpenCV");

// Load the native library.

System.loadLibrary("opencv_java246");

new DetectFaceDemo().run();





//运行结果:

//Hello, OpenCV

//

//Running DetectFaceDemo

///E:/eclipse_Jee/workspace/JavaOpenCV246/bin/com/njupt/zhb/test/lbpcascade_frontalface.xml

//Detected 8 faces

//Writing faceDetection.png
package com.njupt.zhb.test;
public class TestMain
public static void main(String[] args)
System.out.println("Hello, OpenCV");
// Load the native library.
System.loadLibrary("opencv_java246");
new DetectFaceDemo().run();


//运行结果:
//Hello, OpenCV
//
//Running DetectFaceDemo
///E:/eclipse_Jee/workspace/JavaOpenCV246/bin/com/njupt/zhb/test/lbpcascade_frontalface.xml
//Detected 8 faces
//Writing faceDetection.png

opencv QImage与Mat 互转 及简单的图像处理


一、opencv库文件

编译好的opencv 库。

点击这里进行下载

二、使用方式(Qt)

把上面下载的opencv.zip 解压出来的include和lib 文件夹放到工程文件夹里面,并在pro 文件中添加以下代码,即可使用

INCLUDEPATH +=$$PWD\\include

INCLUDEPATH +=$$PWD\\include\\opencv

INCLUDEPATH +=$$PWD\\include\\opencv2

LIBS +=$$PWD\\lib/libopencv_*.a

三、QImage 转 Mat (不太全,多多指教)

通过判断QImage 的类型 在调用Mat 的构造函数进行转换,代码都有进行注释
代码如下(示例):

cv::Mat ImageHandle::QImage2Mat(QImage image)
{
    cv::Mat mat;   //创建一个mat对象来接收
    switch (image.format())  //QImage 的一个库函数 可以返回图片的类型
    {
    case QImage::Format_ARGB32_Premultiplied:  //RGB32 为四通道的所以在调用mat构造函数需要转换成四通道的mat类型(CV_8UC4)
        mat = cv::Mat(image.height(), image.width(), CV_8UC4, (void*)image.constBits(), image.bytesPerLine());
        break;
    case QImage::Format_RGB888:   //RGB888 即RGB24 三通道八位的图片 所以转成三通道的mat(CV_8UC4)
        mat = cv::Mat(image.height(), image.width(), CV_8UC3, (void*)image.constBits(), image.bytesPerLine());
        //因为Qimage 是RGB 通道 而 Mat 为 BGR 通道 所以需要使用cvtcolor进行转换,不然图片通道会颠倒
        cv::cvtColor(mat, mat,cv::COLOR_RGB2BGR); 
        break;
    case QImage::Format_Indexed8:  //Indexed8 为单通道的图片 所以在转换成mat 也是单通道(CV_8UC1)
        mat = cv::Mat(image.height(), image.width(), CV_8UC1, (void*)image.constBits(), image.bytesPerLine());
        break;
    }
    return mat;
}

四、Mat转 QImage

跟上面一样也是通过判断mat的通道 调用QImage的构造函数来进行转换

QImage ImageHandle::Mat2QImage(cv::Mat mat)
{
    if(mat.type() == CV_8UC1)
    {
        QImage image(mat.cols, mat.rows, QImage::Format_Indexed8);
        //转换为qimage 单通道颜色值
        image.setColorCount(256);
        for(int i = 0; i < 256; i++)
        {
            image.setColor(i, qRgb(i, i, i));
        }
        uchar *pSrc = mat.data;
        for(int row = 0; row < mat.rows; row ++)
        {
            uchar *pDest = image.scanLine(row);
            memcpy(pDest, pSrc, mat.cols);
            pSrc += mat.step;
        }
        return image;
    }
    else if(mat.type() == CV_8UC3)
    {
        QImage image((const uchar*)mat.data, mat.cols, mat.rows, mat.step, QImage::Format_RGB888);
        return image.rgbSwapped();
    }
    else if(mat.type() == CV_8UC4)
    {
        const uchar *pSrc = (const uchar*)mat.data;
        QImage image(pSrc, mat.cols, mat.rows, mat.step, QImage::Format_ARGB32);
        return image;
    }
    else
    {
        return QImage();
    }
}

五、一些简单的图像处理操作

1、图片的滤色

通过mat的宽高来访问图片的所有像素点 并删除对应的颜色

QImage ImageHandle::ImageColorDelete(QImage &image, int flag)
{
    cv::Mat mat = this->QImage2Mat(image);
    cv::Mat dst = cv::Mat::zeros(mat.size(),mat.type());
    int chl = mat.channels();
    //遍历像素点 滤除每个像素点所对应的颜色值,从而达到滤色的效果
    for(int row=0;row<mat.rows;row++)
    {
        for(int col=0;col<mat.cols;col++)
        {
            if(chl == 3)
            {
                switch (flag)
                {
                case BLUE:
                    dst.at<cv::Vec3b>(row,col)[0] = 0;
                    dst.at<cv::Vec3b>(row,col)[1] = mat.at<cv::Vec3b>(row,col)[1];
                    dst.at<cv::Vec3b>(row,col)[2] = mat.at<cv::Vec3b>(row,col)[2];
                    break;
                case GREEN:
                    dst.at<cv::Vec3b>(row,col)[0] = mat.at<cv::Vec3b>(row,col)[0];
                    dst.at<cv::Vec3b>(row,col)[1] = 0;
                    dst.at<cv::Vec3b>(row,col)[2] = mat.at<cv::Vec3b>(row,col)[2];
                    break;
                case RED:
                    dst.at<cv::Vec3b>(row,col)[0] = mat.at<cv::Vec3b>(row,col)[0];
                    dst.at<cv::Vec3b>(row,col)[1] = mat.at<cv::Vec3b>(row,col)[1];
                    dst.at<cv::Vec3b>(row,col)[2] = 0;
                    break;
                }

            }
        }
    }
    return this->Mat2QImage(dst);
}

2、图片的反色

操作每个像素点,每个像素点的像素进行取反得到反色效果

QImage ImageHandle::ImageContraryColor(QImage &image)
{
    cv::Mat mat = this->QImage2Mat(image);
    cv::Mat dst = cv::Mat::zeros(mat.size(),mat.type());
    int chl = mat.channels();
    //操作每个像素点,每个像素点的像素进行取反得到反色效果
    for(int row=0;row<mat.rows;row++)
    {
        for(int col=0;col<mat.cols;col++)
        {
            if(chl == 3)
            {
                dst.at<cv::Vec3b>(row,col)[0] = 255 - mat.at<cv::Vec3b>(row,col)[0];
                dst.at<cv::Vec3b>(row,col)[1] = 255 - mat.at<cv::Vec3b>(row,col)[1];
                dst.at<cv::Vec3b>(row,col)[2] = 255 - mat.at<cv::Vec3b>(row,col)[2];
            }
        }
    }
    return this->Mat2QImage(dst);
}

3、图像的提色

遍历像素点 提取所对应的颜色

cv::Mat mat = this->QImage2Mat(image);
    cv::Mat dst = cv::Mat::zeros(mat.size(),mat.type());
    int chl = mat.channels();
    //遍历像素点 提取所对应的颜色
    for(int row=0;row<mat.rows;row++)
    {
        for(int col=0;col<mat.cols;col++)
        {
            if(chl == 3)
            {
                switch (flag)
                {
                case BLUE:
                    dst.at<cv::Vec3b>(row,col)[0] = mat.at<cv::Vec3b>(row,col)[0];
                    dst.at<cv::Vec3b>(row,col)[1] = 0;
                    dst.at<cv::Vec3b>(row,col)[2] = 0;
                    break;
                case GREEN:
                    dst.at<cv::Vec3b>(row,col)[0] = 0;
                    dst.at<cv::Vec3b>(row,col)[1] = mat.at<cv::Vec3b>(row,col)[1];
                    dst.at<cv::Vec3b>(row,col)[2] = 0;
                    break;
                case RED:
                    dst.at<cv::Vec3b>(row,col)[0] =0;
                    dst.at<cv::Vec3b>(row,col)[1] = 0;
                    dst.at<cv::Vec3b>(row,col)[2] = mat.at<cv::Vec3b>(row,col)[2];
                    break;
                }

            }
        }
    }
    return this->Mat2QImage(dst);

刚开始主要还是记录一下自己实现的功能,后面还会进行更新opencv 的图像处理部分

以上是关于Opencv和Qt QImage格式转Mat的主要内容,如果未能解决你的问题,请参考以下文章

[Qt5] Develop openCV3 by QML on Qt-creator

Mat与QImage互相转换

使用QT5绘制OpenCV3的Mat图像

使用QT5绘制OpenCV3的Mat图像

使用 QImage 和 OpenCV 显示图像 [重复]

Qt5和opencv常用函数