一、通过ROI感兴趣区域来裁剪图像
1.1 cv::Rect
示例
#include <opencv2\core.hpp> #include <opencv2\imgcodecs.hpp> #include <opencv2\highgui.hpp> using namespace cv; int main(int argc, char* argv) { Mat src = imread(".\\res\\1.png"); Rect rect(0, 0, 200, 200); Mat roi = src(rect); MatSize roiSize = roi.size; namedWindow("src"); namedWindow("roi", WINDOW_AUTOSIZE); imshow("src", src); imshow("roi", roi); waitKey(0); return 0; }
二、RGB、YUV、GRAY像素格式介绍opencv像素格式转换cvtColor接口讲解
像素格式和灰度图
2.1 RGB、YUV、GRAY
RGB:红绿蓝
YUV:亮度、色度、饱和度
GRAY:0-255表示亮度,颜色没有意义时用灰度图,比如OCR
2.2 cvtColor(src,img,COLOR_BGR2GRAY)
三、手动实现转换灰度图并与opencv提供的函数做性能对比
自己动手实现
转换公式:GRay = (R30 + G59 + B*11 +50)/100
#include <opencv2\core.hpp> #include <opencv2\imgcodecs.hpp> #include <opencv2\highgui.hpp> #include <opencv2\imgproc.hpp> using namespace cv; int PrintMs(const char *text = "") { static long long last = 0; long long cur = getTickCount(); if (last == 0) { last = cur; } long long ms = ((double)(cur - last) / getTickFrequency()) * 1000; if (*text != 0) { printf("%s = %d ms\n", text, ms); } last = getTickCount(); return 0; } void RGBToGray(Mat src, Mat &des) { des.create(src.rows, src.cols, CV_8UC1); for (int r = 0; r < src.rows; r++) { for (int c = 0; c < src.cols; c++) { Vec3b &m = src.at<Vec3b>(r, c); // GRay = (R*30 + G*59 + B*11 +50)/100 int gray = (m[2] * 30 + m[1] * 59 + m[0] * 11 + 50) / 100; des.at<uchar>(r, c) = gray; } } } int main(int argc, char* argv) { Mat src = imread(".\\res\\1.png"); Mat gray; Mat mygray; PrintMs(""); cvtColor(src, gray, COLOR_BGR2GRAY); PrintMs("gray ms"); RGBToGray(src, mygray); PrintMs("mygray ms"); namedWindow("gray"); imshow("gray", gray); namedWindow("mygray"); imshow("mygray", mygray); namedWindow("src"); imshow("src", src); waitKey(0); return 0; }
cvtColor 使用了多线程进行计算 会快很多。
四、通过OpenCV阈值函数threshold实现图像的二值化
4.1 二值化和阈(yu 4)值
4.1.1 二进制阈值化
threshold(gray, bin, 100, 255, THRESH_BINARY);
4.1.2 反二进制阈值化
threshold(gray, ibin, 100, 255, THRESH_BINARY_INV);
示例代码
int main(int argc, char* argv) { Mat src = imread(".\\res\\1.png"); Mat bin; Mat ibin; Mat gray; cvtColor(src, gray, COLOR_BGR2GRAY); //二进制阈值化 threshold(gray, bin, 100, 255, THRESH_BINARY); //反二进制阈值化 threshold(gray, ibin, 100, 255, THRESH_BINARY_INV); namedWindow("src"); namedWindow("bin"); namedWindow("ibin"); imshow("src", src); imshow("bin", bin); imshow("ibin", ibin); waitKey(0); return 0; }
五、通过OpenCV图像亮度和对比度
5.1 对比度和亮度
saturate_cast<uchar>();
在图像处理方面,无论是加是减,乘除,都会超出一个像素灰度值的范围(0~255),saturate_cast函数的作用即是:当运算完之后,结果为负,则转为0,结果超出255,则为255。
六、通过对Mat遍历修改图像亮度和对比度与convertTo性能对比
#include <opencv2\core.hpp> #include <opencv2\imgcodecs.hpp> #include <opencv2\highgui.hpp> #include <opencv2\imgproc.hpp> using namespace cv; int PrintMs(const char *text = "") { static long long last = 0; long long cur = getTickCount(); if (last == 0) { last = cur; } long long ms = ((double)(cur - last) / getTickFrequency()) * 1000; if (*text != 0) { printf("%s = %d ms\n", text, ms); } last = getTickCount(); return 0; } // ///@para a float 对比度 1.0~3.0 ///@para b int 亮度 0~100 void ChangeGain(Mat &src, Mat &des, float a, int b) { //g(r,c) = a*f(r,c) + b des.create(src.rows, src.cols, src.type()); for (int r = 0; r < src.rows; r++) { for (int c = 0; c < src.cols; c++) { for (int i = 0; i < 3; i++) { des.at<Vec3b>(r, c)[i] = saturate_cast<uchar>(a * src.at<Vec3b>(r, c)[i] + b); } } } } int main(int argc, char *argv[]) { //调整对比度和亮度 Mat src = imread(".\\res\\1.png"); Mat des; PrintMs(""); ChangeGain(src, des, 2.0, 50); PrintMs("ChangeGain"); Mat des2; src.convertTo(des2, -1, 2.0, 50); PrintMs("convertTo"); namedWindow("src"); namedWindow("des"); namedWindow("des2"); imshow("src", src); imshow("des", des); imshow("des2", des2); waitKey(0); return 0; }
七、图像尺寸调整算法介绍并手动实现近邻算法
是对图像进行缩放的一种方式
7.1 图像尺寸调整
INTER_NEAREST 近邻算法
性能好 效果差
CV_INTER_LINEAR 双线性内插算法(缺省使用)
性能稍差,但效果好
void xresize(Mat &src, Mat &des, Size size) { des.create(size, src.type()); //映射的原图坐标 int sx, sy = 0; float fx = (float)src.cols / des.cols; float fy = (float)src.rows / des.rows; for (int x = 0; x < des.cols; x++) { sx = fx * x + 0.5; for (int y = 0; y <des.rows; y++) { sy = fy * y + 0.5; des.at<Vec3b>(y, x) = src.at<Vec3b>(sy, sx); } } } int main(int argc, char *argv[]) { Mat src = imread("1.png"); //512*512 256 1024 Mat img256,img1024,des256,des1024; resize(src, des256, Size(256, 256), 0, 0, INTER_NEAREST); PrintMs(); //xresize(src, img256, Size(256, 256)); //PrintMs("img256"); xresize(src, img1024, Size(1024, 1024)); //resize(src, img1024, Size(4024, 4024), 0, 0, INTER_NEAREST); PrintMs("img1024"); //resize(src, des256, Size(1024, 1024), 0, 0, INTER_NEAREST); resize(src, des1024, Size(1024, 1024), 0, 0, INTER_LINEAR); PrintMs("des1024"); namedWindow("src"); //namedWindow("img256"); namedWindow("des1024"); namedWindow("img1024"); imshow("src", src); imshow("img1024", img1024); imshow("des1024", des1024); //imshow("img1024", img1024); waitKey(0); return 0; }
八、调用opencv的resize使用近邻算法并与自定义算法比较
滤波
输入图像中像素的小邻域来产生输出图像的方法,在信号处理中这种方法称为滤波( filtering)。其中,最常用的是线性滤波,输出像素是输入邻域像素的加权和。
双线性内插值
三十分钟理解:线性插值,双线性插值Bilinear Interpolation算法
- 是由源图像位置在它附近的2*2区域4个邻近象素的值通过加权平均计算得出的
- 低通滤波性质,使高频分量受损,图像轮廓可能会有一点模糊
九、高斯金字塔和拉普拉斯金字塔调整图像尺寸详解
图像金字塔
也是对图像进行缩放的一种方式
高斯金字塔(Gaussian pyramid)
用来向下采样缩小
- 获取G(i+1)将G(i)与高斯内核卷积
- 将所有偶数行和列去除
高斯内核
拉普拉斯金字塔(Laplacian pyramid)
用来从金字塔低层图像重建上层未采样图像 放大
- 用来从金字塔低层图像重建上层未采样图像
- 首先,将图像扩大两倍,新增以0填充
示例
int main(int argc, char *argv[]) { Mat src = imread(".\\res\\1.png"); //512*512 256 1024 Mat gsrc; Mat lsrc; pyrDown(src, gsrc); pyrUp(src, lsrc); namedWindow("src"); moveWindow("src", 0, 0); namedWindow("gsrc"); moveWindow("gsrc", 512, 0); namedWindow("lsrc"); moveWindow("lsrc", 0, 512); imshow("src", src); imshow("gsrc", gsrc); imshow("lsrc", lsrc); cvWaitKey(0); return 0; }
十、实现两幅图像混合blending
实现两幅图像混合
- dst = src1a+ src2(1-a)+ gammaa=[0~1]
- 画面叠化( cross-dissolve )效果
- addWeighted( src1, a, src2,1-a, 0.0, dst);
十一、图像旋转和镜像
图像的旋转
cv:: rotate(src, dst, type);
-ROTATE_180
-ROTATE_90_CLOCKWISE
-ROTATE 90 COUNTERCLOCKWISE
图像的镜像
cv:flip(src, dst, type); //type 0(x),1(y),-1
示例
int main(int argc, char *argv[]) { Mat img = imread(".\\res\\1.png"); Mat rot; Mat fl; cv::rotate(img, rot, ROTATE_90_CLOCKWISE); cv::flip(img, fl,1); //type 0(x), 1(y), -1 namedWindow("src"); namedWindow("rot"); namedWindow("fl"); imshow("src", img); imshow("rot", rot); imshow("fl", fl); waitKey(0); return 0; }
十二、通过ROI实现图像并排合并
int main(int argc, char *argv[]) { Mat img1 = imread(".\\res\\1.png"); Mat img2 = imread(".\\res\\2.jpg"); int height = img1.rows; int width1 = img1.cols; int width2 = img2.cols; // 将高图像等比缩放与低图像高度一致 if (img1.rows > img2.rows) { height = img2.rows; width1 = img1.cols * ((float)img2.rows / (float)img1.rows); resize(img1, img1, Size(width1, height)); } else if (img1.rows < img2.rows) { width2 = img2.cols * ((float)img1.rows / (float)img2.rows); resize(img2, img2, Size(width2, height)); } //创建目标Mat Mat des; des.create(height, width1 + width2, img1.type()); Mat r1 = des(Rect(0, 0, width1, height)); img1.copyTo(r1); Mat r2 = des(Rect(width1, 0, width2, height)); img2.copyTo(r2); namedWindow("des"); imshow("des", des); waitKey(0); return 0; }