一、图像叠加

关门放代码

#include <opencv2/opencv.hpp>
#include <iostream>using namespace std;
using namespace cv;int main(int argc, char** argv) {Mat src1, src2, dst;src1 = imread("C:\\Users\\Administrator\\Desktop\\test.jpg");src2 = imread("C:\\Users\\Administrator\\Desktop\\test2.jpg");if (!src1.data) {cout << "could not load image Linux Logo..." << endl;return -1;}if (!src2.data) {cout << "could not load image WIN7 Logo..." << endl;return -1;}double alpha = 0.5;if (src1.rows == src2.rows && src1.cols == src2.cols && src1.type() == src2.type()) {addWeighted(src1, alpha, src2, (1.0 - alpha), 0.0, dst);//将src2设置透明度1.0-alpha后叠加在src1上。// multiply(src1, src2, dst, 1.0);imshow("linuxlogo", src1);imshow("win7logo", src2);namedWindow("blend demo", CV_WINDOW_AUTOSIZE);imshow("blend demo", dst);}else {printf("could not blend images , the size of images is not same...\n");return -1;}waitKey(0);return 0;
}

以上代码中主要的几个知识点解释下:

这里要求两个图像的长宽需要一样。

1.if (!src1.data) {}

这里用于判断图片是否加载成功,如果加载失败则停止运行。

2.addWeighted(src1, alpha, src2, (1.0 – alpha), 0.0, dst);

公式:OpenCV C++开发 第二节:图像处理(四、图像叠加、调整图像亮度与对比度、绘制形状与文字)-编程之家

其中α的取值范围为0~1之间

参数1:输入图像src1

参数2:输入图像src1alpha

参数3:输入图像src2

参数4:输入图像src2alpha

参数5gamma

参数6:输出混合图像

这句代码的意思为:将src2设置透明度1.0-alpha后叠加在src1上存于dst。

看效果

OpenCV C++开发 第二节:图像处理(四、图像叠加、调整图像亮度与对比度、绘制形状与文字)-编程之家

二、调整图像亮度与对比度

#include <opencv2/opencv.hpp>
#include <iostream>using namespace std;
using namespace cv;int main(int argc, char** argv) {Mat src, dst;src = imread("C:\\Users\\Administrator\\Desktop\\test.png");//src2 = imread("C:\\Users\\Administrator\\Desktop\\test1.png");if (!src.data) {printf("could not load image...\n");return -1;}char input_win[] = "input image";//cvtColor(src, src, CV_BGR2GRAY);namedWindow(input_win, CV_WINDOW_AUTOSIZE);imshow(input_win, src);// contrast and brigthtness changes int height = src.rows;int width = src.cols;dst = Mat::zeros(src.size(), src.type());//创建一个空白的图像float alpha = 1.2;float beta = 30;Mat m1;src.convertTo(m1, CV_32F);//默认是CV_8UC转换到CV32Ffor (int row = 0; row < height; row++) {for (int col = 0; col < width; col++) {if (src.channels() == 3) {float b = m1.at<Vec3f>(row, col)[0];// bluefloat g = m1.at<Vec3f>(row, col)[1]; // greenfloat r = m1.at<Vec3f>(row, col)[2]; // red// outputdst.at<Vec3b>(row, col)[0] = saturate_cast<uchar>(b*alpha + beta);dst.at<Vec3b>(row, col)[1] = saturate_cast<uchar>(g*alpha + beta);dst.at<Vec3b>(row, col)[2] = saturate_cast<uchar>(r*alpha + beta);}else if (src.channels() == 1) {float v = src.at<uchar>(row, col);dst.at<uchar>(row, col) = saturate_cast<uchar>(v*alpha + beta);}}}char output_title[] = "contrast and brightness change demo";namedWindow(output_title, CV_WINDOW_AUTOSIZE);imshow(output_title, dst);waitKey(0);return 0;
}

以上代码中主要的几个知识点解释下:

1.dst = Mat::zeros(src.size(), src.type());//返回指定大小和类型的零数组。即创建一个空的图像。

2.src.convertTo(m1, CV_32F);

默认Mat是CV_8UC的Vec3b。
这句的意思是把CV_8UC转换到CV32F的Vec3f。
Vec3b对应三通道的顺序是blue、green、red的uchar类型数据。
Vec3f对应三通道的float类型数据,要比Vec3b更精确。

3.三通道dst.at<Vec3b>(row, col)[0] = saturate_cast<uchar>(b*alpha + beta);

公式:OpenCV C++开发 第二节:图像处理(四、图像叠加、调整图像亮度与对比度、绘制形状与文字)-编程之家

Mat.at<Vec3b>(y,x)[index]=value 给每个像素点每个通道赋值,x与y是像素点。index是通道,rgb通道就是对应012。如果没有赋值则是取值。

4.单通道dst.at<uchar>(row, col) = saturate_cast<uchar>(v*alpha + beta);

与第3点类似,单通道的写法。

5.alpha=1.2;

alpha大于1则更亮,若小于1则偏暗。

如下图,调整后是不是亮瞎了。

OpenCV C++开发 第二节:图像处理(四、图像叠加、调整图像亮度与对比度、绘制形状与文字)-编程之家

三、绘制形状与文字

#include <opencv2/opencv.hpp>
#include <iostream>using namespace std;
using namespace cv;
Mat bgImage;
const char* drawdemo_win = "draw shapes and text demo";
void MyLines();
void MyRectangle();
void MyEllipse();
void MyCircle();
void MyPolygon();
void MyText();
void RandomLineDemo();
int main(int argc, char** argv) {bgImage = imread("C:\\Users\\Administrator\\Desktop\\test.png");if (!bgImage.data) {printf("could not load image...\n");return -1;}MyLines();MyRectangle();MyEllipse();MyCircle();MyPolygon();MyText();namedWindow("random line demo", CV_WINDOW_AUTOSIZE);imshow("random line demo", bgImage);RandomLineDemo();waitKey(0);return 0;
}
/*
画一条线条
*/
void MyLines() {Point p1 = Point(20, 30);Point p2;p2.x = 400;p2.y = 400;Scalar color = Scalar(0, 0, 255);line(bgImage, p1, p2, color, 1, LINE_AA);
}
/*
画一个方形框框
*/
void MyRectangle() {Rect rect = Rect(200, 100, 300, 300);Scalar color = Scalar(255, 0, 0);rectangle(bgImage, rect, color, 2, LINE_8);
}
/*
画一个椭圆框框
*/
void MyEllipse() {Scalar color = Scalar(0, 255, 0);ellipse(bgImage, Point(bgImage.cols / 2, bgImage.rows / 2), Size(bgImage.cols / 4, bgImage.rows / 8), 0, 0, 360, color, 2, LINE_8);
}
/*
画一个圆形框框
*/
void MyCircle() {Scalar color = Scalar(0, 255, 255);Point center = Point(bgImage.cols / 2, bgImage.rows / 2);circle(bgImage, center, 150, color, 2, 8);
}/*
画一个实心方形
*/
void MyPolygon() {Point pts[1][5];pts[0][0] = Point(100, 100);pts[0][1] = Point(100, 200);pts[0][2] = Point(200, 200);pts[0][3] = Point(200, 100);pts[0][4] = Point(100, 100);const Point* ppts[] = { pts[0] };int npt[] = { 5 };Scalar color = Scalar(255, 12, 255);fillPoly(bgImage, ppts, npt, 1, color, 8);
}/*
画一段文字
*/
void MyText() {putText(bgImage, "Hello OpenCV", Point(50, 50), CV_FONT_HERSHEY_COMPLEX, 1.0, Scalar(12, 23, 200), 3, 8);
}
//随机画线段
void RandomLineDemo() {RNG rng(12345);Point pt1;Point pt2;for (int i = 0; i < 100000; i++) {pt1.x = rng.uniform(0, bgImage.cols);pt2.x = rng.uniform(0, bgImage.cols);pt1.y = rng.uniform(0, bgImage.rows);pt2.y = rng.uniform(0, bgImage.rows);Scalar color = Scalar(rng.uniform(0, 255), rng.uniform(0, 255), rng.uniform(0, 255));if (waitKey(50) > 0) {break;}line(bgImage, pt1, pt2, color, 1, 8);imshow("random line demo", bgImage);}
}

以上代码中主要的几个知识点解释下:

该段代码中如果分辨不清画的图与对应的代码,可以分别注释某一些代码,一段一段运行。

1.line(bgImage, p1, p2, color, 1, LINE_AA);

画一条线,bgImage是要绘画的目的图像。p1是Point起点。p2是Point终点。color是Scalar类型颜色。1是代表粗细。LINE_AA是线的类型,(LINE_4\LINE_8\LINE_AA),LINE_4与LINE_8都有锯齿,LINE_AA没有锯齿。

2.rectangle(bgImage, rect, color, 2, LINE_8);

画一个方形框框,bgImage是要绘画的目的图像。rect是Rect类型对象,rect内包括起点xy与终点xy。color是Scalar类型颜色。2代表粗细,LINE_8代表有锯齿的类型。

3.ellipse(bgImage, Point(bgImage.cols / 2, bgImage.rows / 2), Size(bgImage.cols / 4, bgImage.rows / 8), 0, 0, 360, color, 2, LINE_8);

画一个椭圆框框。首先我们理解一下椭圆【椭圆是平面内到定点F1、F2的距离之和等于常数(大于|F1F2|)的动点P的轨迹,F1、F2称为椭圆的两个焦点。其数学表达式为:|PF1|+|PF2|=2a(2a>|F1F2|)。椭圆有一个长半轴,就是原点到最远的顶点的距离。一个短半轴,原点到最近的顶点的距离】。

bgImage是要绘画的目的图像。Point(bgImage.cols / 2, bgImage.rows / 2)代表原点即是中心点的位置。Size(bgImage.cols / 4, bgImage.rows / 8)左边的数是长半轴,右边是短半轴。第一个0是旋转角度。第二个0是起点角度。360是终点角度。color是Scalar类型颜色。2代表粗细,LINE_8代表有锯齿的类型。

4.circle(bgImage, center, 150, color, 2, 8);

画一个圆形。center代表原点即是中心点的位置。150是半径。color是Scalar类型颜色。2代表粗细,LINE_8代表有锯齿的类型。8其实就是LINE_8,可以在Visual Studio里按住Ctrl+鼠标点击LINE_8,就会跳转到LINE_8的定义。

5.fillPoly(bgImage, ppts, npt, 1, color, 8);

画一个实心方形。bgImage是要绘画的目的图像。ppts是一个二维数组。npt是多边形顶点数目。1是多边形数量。color是Scalar类型颜色。8代表有锯齿的类型。

6.rng.uniform(0, bgImage.cols);

产生一个0到bgImage.cols之间的整型随机数。

7.waitKey(50)

waitKey()与waitKey(0)都是无限等待。

waitKey(50)是等待50毫秒,继续运行。

来看看效果

OpenCV C++开发 第二节:图像处理(四、图像叠加、调整图像亮度与对比度、绘制形状与文字)-编程之家

这节就这么多,这些代码只要记住都是什么功能就行,不用背下来,等到了使用的时候再查。还有一些原理需要看懂。