一、opencv和Qt的环境搭建。
网上有很多资料,所以我也是依照网上资料进行,主要是对opencv库的编译以及Qt对opencv的使用。
需要下载所需版本的opencv的源码,另外需要一个cmake工具。 我下载的opencv版本是3.2.0版本,通过cmake后在使用VS2013进行编译得到最终的库文件。
然后在Qt中就可以像一般的添加库方式添加。
另外想说明的是,最好是将编译得到的文件,放到一个指定目录,将其中的头文件和库文件路径添加到环境变量中,这样会方便你的开发。
(要注意的是,如果你之后改变了这个文件的路径,记得环境变量也要进行修改,不然Qt中程序崩溃而且不容易发现这个问题)
二、opencv的初步接触
推荐大家去了解opencv的基础数据类型。
以下是我学习时用到的两个博主的网站:
源码阅读 以及 一些类类型说明
另外推荐一个网站,但是都是英文需要慢慢阅读。 opencv的api说明
三、练习代码
我习惯的学习方法是,练习一些基础功能、函数。并且在运行中记录错误增加自己理解的备注,方便以后复查和看代码时快速理解。
所以这里都是记录的一些练习,有自己的一些注释。
我的Qt的pro文件配置,以后不再重复:
INCLUDEPATH += $$PWD/install/include \
$$PWD/install/include/opencv \
$$PWD/install/include/opencv2
CONFIG(debug, debug|release): {
LIBS += -L$$PWD/install/x86/vc12/lib
LIBS += -lopencv_calib3d320d \
-lopencv_core320d \
-lopencv_features2d320d \
-lopencv_flann320d \
-lopencv_highgui320d \
-lopencv_imgcodecs320d \
-lopencv_imgproc320d \
-lopencv_ml320d \
-lopencv_objdetect320d \
-lopencv_photo320d \
-lopencv_shape320d \
-lopencv_stitching320d \
-lopencv_superres320d \
-lopencv_video320d \
-lopencv_videoio320d \
-lopencv_videostab320d
} else:CONFIG(release, debug|release): {
LIBS += -L$$PWD/install/x86/vc12/lib
LIBS += -lopencv_calib3d320 \
-lopencv_core320 \
-lopencv_features2d320 \
-lopencv_flann320 \
-lopencv_highgui320 \
-lopencv_imgcodecs320 \
-lopencv_imgproc320 \
-lopencv_ml320 \
-lopencv_objdetect320 \
-lopencv_photo320 \
-lopencv_shape320 \
-lopencv_stitching320 \
-lopencv_superres320 \
-lopencv_video320 \
-lopencv_videoio320 \
-lopencv_videostab320
}
View Code
练习代码:
#include "widget.h"
#include <QApplication>
#include <opencv2/opencv.hpp>
#include <stdio.h>
#include <QDebug>
#if _MSC_VER >= 1600
#pragma execution_character_set("utf-8")
#endif
using namespace std;
using namespace cv;
void createAlphaMat(Mat& mat){
for(int i = 0; i < mat.rows; i++){
for(int j = 0; j < mat.cols; j++){
Vec4b &rgba = mat.at<Vec4b>(i, j);
rgba[0] = UCHAR_MAX;
rgba[1] = saturate_cast<uchar>(float((mat.cols) - j)
/ ((float)mat.cols) * UCHAR_MAX);
rgba[2] = saturate_cast<uchar>(float((mat.cols) - i)
/ ((float)mat.rows) * UCHAR_MAX );
rgba[3] = 0;
}
}
}
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
//Widget w;
//w.show();
/**显示图片
Mat image = imread("C:\\Users\\zhangenhao\\Desktop\\IMG_000000011.jpg");
Mat im(4,4,CV_8U,Scalar(101,102,103));
cvNamedWindow("windows", CV_WINDOW_NORMAL);
imshow("windows", image);
//返回矩阵通道的数量
qDebug() << "mat channels:" << image.channels();
waitKey(0);
*/
/**自画图像并保存
Mat mat(480, 640, CV_8UC4);
createAlphaMat(mat);
namedWindow("image", CV_WINDOW_AUTOSIZE);
imshow("image", mat);
//保存失败
vector<int> compression_params;
compression_params.resize(2);
compression_params[0] = CV_IMWRITE_PNG_COMPRESSION;
compression_params[1] = CV_IMWRITE_PNG_COMPRESSION;
//compression_params.push_back(CV_IMWRITE_PNG_COMPRESSION);
qDebug() << compression_params.size();
imwrite("./genera.png", mat, compression_params);
**/
/** 方框滤波 均值滤波 高斯滤波
namedWindow("原图", CV_WINDOW_NORMAL);
namedWindow("Box效果图");
namedWindow("Blur效果图");
namedWindow("Gauss效果图");
Mat srcImg = imread("C:\\Users\\zhangenhao\\Desktop\\IMG_000000011.jpg");
imshow("原图", srcImg);
Mat Boxout;
boxFilter(srcImg, Boxout, -1, Size(7, 7));
imshow("Box效果图", Boxout);
Mat Blurout;
blur(srcImg, Blurout, Size(7, 7));
imshow("Blur效果图", Blurout);
Mat Gauss;
GaussianBlur(srcImg, Gauss, Size(7, 7), 0, 0);
imshow("Gauss效果图", Gauss);
**/
/**图像制式转化 cvtColor
Mat image = imread("C:\\Users\\zhangenhao\\Desktop\\IMG_000000011.jpg");
Mat ret;
cvtColor(image, ret, CV_RGB2GRAY);//转为灰度图
cvNamedWindow("windows", CV_WINDOW_NORMAL);
imshow("windows", ret);
//返回矩阵通道的数量
qDebug() << "mat channels:" << image.channels();
cout << "mat :" << endl << image << endl;
waitKey(0);
**/
/**
//unsigned char 0~255
//char -128~127
Mat A = (Mat_<unsigned char>(3, 3) << 1,2,3,4,5,6,7,8,9);
cout << "A =" << endl << A <<endl;
cout << "A.t() =" << endl << A.t() << endl;
Mat B = A.t();
cout << "B =" << endl << B << endl;
//row,column 赋值某个像素点
B.at<unsigned char>(1, 2) = 10;
cout << "after assigning value to B." << endl;
cout << "A = " << endl << A << endl;
cout << "B = " << endl << B << endl;
Mat C = A.clone();
//全部+1,减法也适用
C += 1;
cout << "C += 1 ->" << endl << C << endl;
C -= 1;
//按照参数类型确定最大值最小值
C = A.clone();
C += 250;
cout << "C += 250 ->" << endl << C << endl;
C = A.clone();
C -= 250;
cout << "C -= 250 ->" << endl << C << endl;
C = A.clone();
// 全部*10
C *= 10;
cout << "C *= 10 ->" << endl << C << endl;
C = A.clone();
//矩阵相加、相减
C += A;
cout << "C += A ->" << endl << C << endl;
C -= A;
cout << "C -= A ->" << endl << C << endl;
Mat D;
A.convertTo(D, CV_32FC1);// Only CV_32FC1, CV_32FC2, CV_64FC1 and, CV_64FC2
//能够被用于矩阵乘法
cout << "D = " << endl << D << endl;
D *= D;
cout << "D *= ->" << endl << D << endl;
Mat DD = A.clone();
cout << "DD.type() = " << DD.type() << endl;
cout << "DD = " << endl << DD << endl;
DD.convertTo(DD, CV_64FC1);
cout << "DD.type() = " << DD.type() << endl;
cout << "DD = " << endl << DD << endl;
DD *= 100;
cout << "DD *= ->" << endl << DD << endl;
DD.convertTo(DD, CV_8UC1);
cout << "DD convert to CV_8UC1 ->" << endl << DD <<endl;
//type和depth应该是一样的,表示每个像素的位数
Mat E;
//E = D + A;//error,runtime exception
add(A, D, E, cv::Mat(), CV_32SC1);
cout << "E = " << endl << DD << endl;
cout << "E.type() =" << endl << E.type() << endl;
B = 250;
add(B, D, E, cv::Mat(), CV_32SC1);
cout << "B=250 ,E = B + D with CV_32SC1 ->" << endl
<< E << endl;
cout << "E->depth: "<< endl << E.depth()<< endl;
cv::add(B, D, E, cv::Mat(), CV_8UC1);
std::cout << "B = 250, E = B + D with CV_8UC1 -> " << std::endl
<< E << std::endl << std::endl;
cout << "E->depth: "<< endl << E.depth()<< endl;
cout << "E->channels:"<<endl << E.channels()<<endl;
//创建一个7*7的矩阵,类型为CV_32F,C3表示是3通道。
//scalar是对矩阵进行初始化赋值,第一个通道为1,第二个为3,第三个为5
Mat M(7, 7, CV_32FC3, Scalar(1, 3, 5));
cout << "M =" << endl << M << endl;
//3通道修改某个像素点的值,可以通过循环M的行、列修改所有的像素点值
Vec3f pix;
pix[0] = 2;
pix[1] = 5;
pix[2] = 8;
M.at<Vec3f>(0, 0) = pix;
//单独修改 某个像素点的某条通道,三通道0、1、2
M.at<Vec3f>(1, 1)[1] = 10;
cout << "M =" << endl << M << endl;
**/
/*图片线性叠加
Mat srcImage1 = imread("./hehua.jpg");
Mat srcImage2 = imread("./shuimu.jpg");
Mat desImage;
if(srcImage1.empty() || srcImage2.empty()){
cout << "图像加载失败" << endl;
return -1;
}
double alpha = 0.2;
double beta = 1.0 - alpha;
namedWindow("线性混合", WINDOW_NORMAL);
//1图,线性混合1图权重,2图,线性混合2图权重,添加到每一个线性总和的gamma值,目标图像
addWeighted(srcImage1, alpha, srcImage2, beta, 0.0, desImage);
imshow("线性混合", desImage);
namedWindow("img1", WINDOW_NORMAL);
imshow("img1", srcImage1);
namedWindow("img2", WINDOW_NORMAL);
imshow("img2", srcImage2);
waitKey(0);
*/
/*不同大小图片的线性混合
Mat srcImage = imread("./maomi.jpg");
Mat addImage = imread("./hehua.jpg");
Mat maskImage = imread("./hehua.jpg", IMREAD_GRAYSCALE);//灰度图
if(srcImage.empty() || addImage.empty()){
cout << "加载失败。" << endl;
return 0;
}
imshow("srcImage", srcImage);
imshow("addImage", addImage);
//通过Rect函数设置ROI区域,可以调节图片的权重
//出来的imageROI,按照addImage图像的大小切下来的srcImage大小。
//Rect前两个参数表示图像的坐标,然后才是矩形的长宽(多少列就是长,多少行就是宽)
//imageROI不是srcImage的副本,是和srcImage矩阵的头指针关联,如果修改了
//imageROI,那么srcImage也会相应改变。所以ROI是srcImage的感兴趣区域
//Mat imageROI = srcImage(Rect(50, 50, addImage.cols, addImage.rows));
//addWeighted(imageROI, 0.7, addImage, 0.3, 0, imageROI);
//以Range()函数设置ROI区域,不能调节权重
//第一个Rang表示行采取关联的行范围,第二个Rang表示采取关联的列范围
Mat imageROI = srcImage(Range(50, 50+maskImage.rows), Range(50, 50+maskImage.cols));
//这里应该是把maskImage的非零元素复制给imageROI,但是addImage做了什么?
//这里imageROI被改变,相应的srcImage的对应矩阵部分改变
addImage.copyTo(imageROI, maskImage);
imshow("hunhe", srcImage);
*/
return a.exec();
}
View Code
其中每一段功能都以/** **/分隔,方便测试。
注:imwrite();这个接口,如果在pro中不分debug和release编译,直接加载所有的库文件,在debug的时候是会出错的,保存不了图片,release则没问题。所以pro中区分了编译加载。