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

13 篇文章 1 订阅

一、图像叠加

关门放代码

#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);

公式:

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

参数1:输入图像src1

参数2:输入图像src1alpha

参数3:输入图像src2

参数4:输入图像src2alpha

参数5gamma

参数6:输出混合图像

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

看效果

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

#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转换到CV32F
	for (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];// blue
				float g = m1.at<Vec3f>(row, col)[1]; // green
				float r = m1.at<Vec3f>(row, col)[2]; // red

				// output
				dst.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);

公式:

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则偏暗。

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

三、绘制形状与文字

#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毫秒,继续运行。

来看看效果

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

  • 2
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值