图像操作(反差,混合,调整图像亮度与对比度,绘制文字)

一、反差:

1、灰度图像反差

int gray = gray_src.at(row, col); &nbsp //得到像素点的值
gray_src.at(row, col)=255-gray;//反差

演示代码:

int main(int argc,char**argv)
{
	Mat src,gray_src;
	src = imread("D:/PT/test.jpg");
	if (src.empty())
	{
		cout << "liangliang" << endl;
		return -1;
	}
	namedWindow("input", CV_WINDOW_AUTOSIZE);
	imshow("input", src);
	//cvtColor(src, gray_src, CV_BGR2GRAY);
	//namedWindow("output", CV_WINDOW_AUTOSIZE);
	//imshow("output", gray_src);
	int height = gray_src.rows;
	int width = gray_src.cols;
 	for (int row = 0; row < height; row++)
	{
		for (int col = 0; col < width; col++)
		{
			int gray = gray_src.at<uchar>(row, col);
			gray_src.at<uchar>(row, col)=255-gray;//反差
		}
	}
	namedWindow("output", CV_WINDOW_AUTOSIZE);
	imshow("output", gray_src);
	//waitKey(2000);
	//destroyWindow("output");   //等两秒自动销毁
	waitKey(0);
	return 0;

2、彩色图像反差

	printf("src=%d", src.cols);
	cvtColor(src, gray_src, CV_BGR2GRAY); 
	printf("gray_src=%d", gray_src.cols);
彩色图像的cols和灰度图像的cols是一样的,此图为证:

在这里插入图片描述

#include<iostream>
#include<opencv2/opencv.hpp>
using namespace std;
using namespace cv;

int main(int argc,char**argv)
{
	Mat src,gray_src;
	src = imread("D:/PT/test.jpg");
	if (src.empty())
	{
		cout << "liangliang" << endl;
		return -1;
	}
	//printf("src=%d", src.cols);
	//cvtColor(src, gray_src, CV_BGR2GRAY); 
	//printf("gray_src=%d", gray_src.cols);
	Mat dst,dst2;
	dst.create(src.size(), src.type());
	dst2.create(src.size(), src.type());
	int height = src.rows;
	int width = src.cols;
	int nc = src.channels();
	for (int row = 0; row < height; row++)
	{
		for (int col = 0; col < width; col++)
		{
			if (nc == 1)
			{
				int gray = gray_src.at<uchar>(row, col);
				gray_src.at<uchar>(row, col) = 255 - gray;//反差
			}
			else if (nc == 3)
			{

				int b = src.at<Vec3b>(row, col)[0];
				int g = src.at<Vec3b>(row, col)[1];
				int r = src.at<Vec3b>(row, col)[2];        //彩色图像的cols和灰度图像的cols是一样的
				dst.at<Vec3b>(row, col )[0]= 255 - b;
				dst.at<Vec3b>(row, col)[1] = 255 - g;
				dst.at<Vec3b>(row, col)[2] = 255 - r;

				//dst2.at<Vec3b>(row, col)[0] = b;
				//dst2.at<Vec3b>(row, col)[1] = g;
				//dst2.at<Vec3b>(row, col)[2] = r;

				gray_src.at<uchar>(row, col) = min(r, min(b, g));
			}
			
		}
	}
	namedWindow("output", CV_WINDOW_AUTOSIZE);
	imshow("output", gray_src);
	//waitKey(2000);
	//destroyWindow("output");
	waitKey(0);
	return 0;
}
API实现:
	bitwise_not(src, dst);
	namedWindow("output2", CV_WINDOW_AUTOSIZE);

在这里插入图片描述

在这里插入图片描述

二、混合:

相关API (addWeighted)

理论-线性混合操作

演示代码:
//图像混合
Mat src1, src2, dest;
src1 = imread("D:/vcprojects/images/LinuxLogo.jpg");
src2 = imread("D:/vcprojects/images/win7logo.jpg");
if (!src1.data) {
	printf("could not load LinuxLogo image...\n");
	return -1;
}
if (!src2.data) {
	printf("could not load win7logo image...\n");
	return -1;
}
if (src1.rows == src2.rows && src1.cols == src2.cols) {
	double alpha = 0.5;
	namedWindow("line-blend", CV_WINDOW_AUTOSIZE);
	addWeighted(src1, (1 - alpha), src2, alpha, 0.0, dest);

	imshow("line-blend", dest);
	waitKey(0);
	return 0;
}
else {
	printf("image size is not same...\n");
	return -1;
}

三、调整图像亮度与对比度:

演示代码:
//调整图像对比度
#include<iostream>
#include<opencv2/opencv.hpp>
using namespace std;
using namespace cv;

int main(int argc, char** argv)
{
	Mat src, dst;
	src = imread("D:/PT/liner2.jpg");
	if (!src.data)
	{
		cout << "liangliang" << endl;
		return -1;
	}
	char input_win[] = "input image";
	//cvtColor(src, src, COLOR_BGR2GRAY);
	namedWindow("input_win", CV_WINDOW_AUTOSIZE);
	imshow("input_win", src);
	
	int height = src.rows;
	int width = src.cols;
	dst = Mat::zeros(src.size(), src.type());
	float alpha = 0.4;
	float beta = 10;
	Mat m1;
	//src.convertTo(m1, CV_32F);
	for(int row=0;row<height;row++)
		for (int col = 0; col < width; col++)
		{
			if (src.channels() == 3)
			{
				float b = src.at<Vec3b>(row, col)[0];
				float g = src.at<Vec3b>(row, col)[1];
				float r = src.at<Vec3b>(row, col)[2];
				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(-1);
	return 0;
}

在这里插入图片描述
在这里插入图片描述

四、绘制文字:

随机数生成cv::RNG:
  • 生成高斯随机数gaussian (double sigma)
  • 生成正态分布随机数uniform (int a, int b)
putText函数中设置fontFace(cv::HersheyFonts) :
  • fontFace, CV_FONT_HERSHEY_PLAIN
  • fontScale , 1.0, 2.0~ 8.0
opencv字体:
标志名称描述
CV_FONT_HERSHEY_SIMPLEX正常尺寸sans-serif字体
CV_FONT_HERSHEY_PLAIN小尺寸sans-serif字体
CV_FONT_HERSHEY_DUPLEX正常尺寸sans-serif, 比CV_FONT_HERSHEY_SIMPLEX更复杂
CV_FONT_HERSHEY_COMPLEX正常尺寸serif, 比CV_FONT_HERSHEY_DUPLE更复杂
CV_FONT_HERSHEY_TRIPLEX正常尺寸serif, 比CV_FONT_HERSHEY_COMPLEX更复杂
CV_FONT_HERSHEY_COMPLEX_SMALLCV_FONT_HERSHEY_SCRIPT_SIMPLEX
CV_FONT_HERSHEY_SCRIPT_COMPLEXCV_FONT_HERSHEY_SCRIPT_SIMPLEX更复杂的风格
OpenCV中用RNG产生随机数(C++):

产生随机数是编程中经常要用到的操作。C和C++中产生随机数的方法如rand()、 srand() 等在OpenCV中仍可以用。此外,OpenCV还特地编写了C++的随机数类RNG,C的随机数类CvRNG,还有一些相关的函数,使用起来更加方便。

说明
1、关键字前带cv的都是C里的写法,不带cv的是C++里的写法,比如CvRNG和RNG,其本质都是一样的。
2、计算机产生的随机数都是伪随机数,是根据种子seed和特定算法计算出来的。所以,只要种子一定,算法一定,产生的随机数是相同的
3、要想产生完全不重复的随机数,可以用系统时间做种子。OpenCV中用GetTickCount(),C 中用time()

OpenCV中的C++版本随机数:

RNG类是opencv里C++的随机数产生器。它可产生一个64位的int随机数。目前可按均匀分布和高斯分布产生随机数。随机数的产生采用的是Multiply-With-Carry算法和Ziggurat算法。
1、产生一个随机数:

 RNG  可以产生3种随机数
 
 RNG(int seed)         使用种子seed产生一个64位随机整数,默认-1
 RNG::uniform( )       产生一个均匀分布的随机数
 RNG::gaussian( )      产生一个高斯分布的随机数

注:
RNG::uniform(a, b ) 返回一个[a,b)范围的均匀分布的随机数,a,b的数据类型要一致,而且必须是int、float、double中的一种,默认是int。
RNG::gaussian( σ) 返回一个均值为0,标准差为σ的随机数。
         如果要产生均值为λ,标准差为σ的随机数,可以λ+ RNG::gaussian( σ)

//创建RNG对象,使用默认种子“-1”  
RNG rng; 

//产生64位整数  
int N1 = rng; 

/*-------------产生均匀分布的随机数uniform和高斯分布的随机数gaussian---------*/  
//总是得到double类型数据0.000000,因为会调用uniform(int,int),只会取整数,所以只产生0   
double N1a = rng.uniform(0,1);  

//产生[0,1)范围内均匀分布的double类型数据  
double N1b = rng.uniform((double)0,(double)1); 

//产生[0,1)范围内均匀分布的float类型数据,注意被自动转换为double了。  
double N1c = rng.uniform(0.f,1.f); 

//产生[0,1)范围内均匀分布的double类型数据。  
double N1d = rng.uniform(0.,1.); 

//可能会因为重载导致编译不通过(确实没通过。。)     
//double N1e = rng.uniform(0,0.999999); 

//产生符合均值为0,标准差为2的高斯分布的随机数  
double N1g = rng.gaussian(2); 

注:rng既是一个RNG对象,也是一个随机整数。

2、返回下一个随机数:

上面一次只能返回一个随机数,实际上系统已经生成一个随机数组。如果我们要连续获得随机数,没有必要重新定义一个RNG类,只需要取出随机数组的下一个随机数即可。

RNG rng;
int N2 = rng.next();                    //返回下一个随机整数,即N1.next(); 
//返回下一个指定类型的随机数
int N2a = rng.operator uchar();         //返回下一个无符号字符数
int N2b = rng.operator schar();         //返回下一个有符号字符数
int N2c = rng.operator ushort();        //返回下一个无符号短型
int N2d = rng.operator short int();     //返回下一个短整型数
int N2e = rng.operator int();           //返回下一个整型数 
int N2f = rng.operator unsigned int();  //返回下一个无符号整型数
int N2g = rng.operator float();         //返回下一个浮点数 
int N2h = rng.operator double();        //返回下一个double型数
int N2i = rng.operator ()();            //和rng.next( )等价
int N2j = rng.operator ()(100);         //返回[0,100)范围内的随机数 

3、用随机数填充矩阵 RNG::fill( ):

void fill( InputOutputArray mat, int distType, InputArray a, InputArray b, bool saturateRange=false );

参数说明:
InputOutputArray                    输入输出矩阵,最多支持4通道,超过4通道先用reshape()改变结构
int distType                        UNIFORM 或 NORMAL,表示均匀分布和高斯分布
InputArray a                           disType是UNIFORM,a表示为下界(闭区间);disType是NORMAL,a均值
InputArray b                           disType是UNIFORM,b表示为上界(开区间);disType是NORMAL,b标准差
bool saturateRange=false     
	只针对均匀分布有效。当为真的时候,会先把产生随机数的范围变换到数据类型的范围,再产生随机数;
	如果为假,会先产生随机数,再进行截断到数据类型的有效区间。请看以下fillM1和fillM2的例子并观察结果 

//产生[1,1000)均匀分布的int随机数填充fillM  
Mat_<int>fillM(3,3);
rng.fill(fillM,RNG::UNIFORM,1,1000);  

Mat fillM1(3,3,CV_8U); 
rng.fill(fillM1,RNG::UNIFORM,1,1000,TRUE); 

Mat fillM2(3,3,CV_8U); 
rng.fill(fillM2,RNG::UNIFORM,1,1000,FALSE); 

//fillM1产生的数据都在[0,,255)内,且小于255;
//fillM2产生的数据虽然也在同样范围内,但是由于用了截断操作,所以很多数据都是255,  

//产生均值为1,标准差为3的随机double数填进fillN  
Mat_<double>fillN(3,3); 
rng.fill(fillN,RNG::NORMAL,1,3);

4、RNG& rng=theRNG();

RNG& rng=theRNG();
double x= (double)rng;
float  y= (float)rng;
int    z= (int)rng;

5、产生不重复的随机数:
采取另一种方式,用系统时间作为种子初始化rng

RNG rng((unsigned)time(NULL));//当然,用这个要记得加上头函数<time.h>

开始生成随机数

double x=rng.uniform((double)0,(double)255);
float y=rng.uniform(0.f,255.f);
int z=rng.uniform((int)0, (int)255 );

6、randShuffle( ) 将原数组(矩阵)打乱:

randShuffle
( 
	InputOutputArray dst,     输入输出数组(一维)
    double iterFactor=1. ,     决定交换数值的行列的位置的一个系数...
    RNG* rng=0               (可选)随机数产生器,0表示使用默认的随机数产生器,即seed=-1。rng决定了打乱的方法
)
puttext演示代码:
#include<iostream>
#include<opencv2/opencv.hpp>
using namespace std;
using namespace cv;

Mat src, bgImage;
void Myline();
void MyRectangle();
void MyEllipse();
void MyCircle();
void Mypolygon();
void RandomLineDemo();
int main(int argc, char** argv)
{
	
	src = imread("D:/PT/dln.jpg");
	if (src.empty())
	{
		cout << "liangliang" << endl;
		return -1;
	}
	double scale = 0.5;
	Size dsize = Size(src.cols * scale, src.rows * scale);
	Mat dst = Mat(dsize, CV_32S);
	resize(src, bgImage, dsize);

	Myline();//画线
	MyRectangle();
	MyEllipse();
	MyCircle();
	Mypolygon();

	//putText(bgImage, "Hello OpenCV", Point(bgImage.cols / 2, bgImage.rows / 2), CV_FONT_HERSHEY_COMPLEX, 3.0, Scalar(12, 255, 200), 3, 8);
	//尺寸因子,颜色,线条宽度,线型(4邻域,8邻域)
	                                                                                                   //大小                       宽度
	namedWindow("input", CV_WINDOW_AUTOSIZE);
	imshow("input", bgImage);
	//RandomLineDemo();
	waitKey(0);
	return 0;
}


void Myline()//画线
{
	Point p1 = Point(20, 30);
	Point p2;
	p2.x = 300;
	p2.y = 300;
	Scalar color = Scalar(0, 0, 255);
	line(bgImage, p1, p2, color, 8, LINE_AA);//4,8
	//8邻接,4邻接,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), 30, 0, 160, color, 2, LINE_8);
	                                                                                      //椭圆是angle 角度,椭圆在0和360度之间延伸一个弧
}
void MyCircle()//圆形
{

	Scalar color = Scalar(0, 255, 255);
	Point center = Point(bgImage.cols / 2, bgImage.rows / 2);
	circle(bgImage, center, 300, color, 2, LINE_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 RandomLineDemo()
{
	RNG rng(12345);
	Point pt1;
	Point pt2;
	Mat bg = Mat::zeros(bgImage.size(), bgImage.type());
	namedWindow("randow line demo", CV_WINDOW_AUTOSIZE);
	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(bg, pt1, pt2, color, 1, 8);
		imshow("randow line demo", bg);
	}

}

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值