图像操作

本文详细介绍了使用OpenCV进行图像处理的方法,包括读写像素、修改像素值、图像灰度转换及反转等操作。通过具体代码示例展示了如何利用ptr和at函数处理单通道和多通道图像,并探讨了图像复制、构造函数创建Mat对象等方面的内容。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

图像操作读写像素修改像素值  : 计算程序执行时间  : 处理像素范围

读写像素修改像素值 用函数at<>())

opencv中使用vec可表示向量,用于矩阵元素的表达





矩阵元素的表达:
对于单通道图像,其元素类型一般为 8U (即 8位无符号整数),当然也可以 是 16S 、32F32F 等;这些类型可以直接用 uchar 、short 、float等 C/C++语言中的基本数据类型表达。

备注:数据类型 Scalar 以及 Point。


如果多通道图像,如RGB彩色图像,需要用三个通道来表示。在这种情况 下,如果依然将图像视作一个二维矩阵那么矩阵的元素不再是基本数据类型。


不同的图片的属性,at读取像素值的格式不同,请注意。

读写像素修改像素值 用uchar* ptr(int i) ) 

单通道图像




多通道图像



综上
1、通俗讲,ptr所返回的指针指向的是一个一个的通道。

2、ptr所返回的指针,它的初始值一定是行的首地址
uchar* p = src.ptr(0)  当i = 0时,p指向的是第一行的首地址。
p+1  -->  指向第一行的第二个元素的
...
接下来每加1,便指向一个元素的地址,不用管在哪一行了。


备注:
C++的cout输出字符型指针有要求的,看C++未知世界笔记有写。


计算程序执行时间
double t =getTickCount();
//...
double timeconsume = (getTickCount() - t)/getTickFrequency();
printf("time consume: %0.2f \n",timeconsume);


像素范围处理
saturate_cast<>()  防止数据溢出
模板函数  <>这里填的是数据类型 ,即限制每个像素点的取值范围,即像素的深度 
例如
saturate_cast<uchar>             确保数据在0-255之间 
saturate_cast<uchar>(-100)   返回值为0
saturate_cast<uchar>(300)     返回值255
saturate_cast<uchar>(200)     返回值200

代码示例如下:
#include <opencv2/opencv.hpp>
#include <iostream>
#include <math.h>

using namespace std;
using namespace cv;

int main(int argc, char** argv)
{
	Mat src = imread("liaowenbin.bmp");
	namedWindow("original_pic", WINDOW_AUTOSIZE);
	imshow("original_pic", src);

	//证明完全复制的独立性
#if 1
	Mat allCopy = src.clone();
#else
	Mat allCopy;
	src.copyTo(allCopy);
#endif
	int sun_channel = allCopy.rows * allCopy.cols 
		                          * allCopy.channels();
	uchar* p_point = allCopy.ptr(0);
	for (int channel = 0; channel < sun_channel; channel++)
	{
		*(p_point + channel) = 0;
	}

	namedWindow("src.copyTo",WINDOW_AUTOSIZE);
	imshow("src.copyTo",allCopy);

	//cvtColor转灰度图像
	Mat dst;
	cvtColor(src,dst,CV_BGR2GRAY);
	namedWindow("GRAY",WINDOW_AUTOSIZE);
	imshow("GRAY", dst);


	//cvtColor不可逆
#if 0
	Mat A;
	cvtColor(dst, A, CV_GRAY2BGR);
	namedWindow("Output_RGB", WINDOW_AUTOSIZE);
	imshow("Output_RGB", A);
#endif

	int height = dst.rows;//行数
	int weight = dst.cols;//列数

	cout << "height = " << height << endl;
	cout << "weight = " << weight << endl;
	cout << "depth  = " << dst.depth() << endl;
	
	//用 at<>()函数 处理单通道
	//Point pnt;
	for(int rows = 0;rows < height;rows++)
		for (int cols = 0;cols <weight;cols++)
		{
			int sca = dst.at<uchar>(rows,cols);
			dst.at<uchar>(rows, cols) = 255 - sca;//反转
		}
	namedWindow("GRAY_channe1_turn",WINDOW_AUTOSIZE);
	imshow("GRAY_channe1_turn",dst);

	
	//用 at<>()函数 处理多通道	
	Mat A(src);
	for (int rows = 0; rows < height; rows++)
		for (int cols = 0; cols <weight; cols++)
		{
			int b = A.at<Vec3b>(rows, cols)[0];
			int g = A.at<Vec3b>(rows, cols)[1];
			int r = A.at<Vec3b>(rows, cols)[2];
			A.at<Vec3b>(rows, cols)[0] = 255 - b;//反转
			A.at<Vec3b>(rows, cols)[1] = 255 - g;
			A.at<Vec3b>(rows, cols)[2] = 255 - r;
		}
	namedWindow("RGB_channel3_turn", WINDOW_AUTOSIZE);
	imshow("RGB_channel3_turn", A);

	//证明了单纯复制对象的头和指针部分时,不会复制数据部分,
	//但是通过操作新的对象时,会影响到我们的旧的对象。
	namedWindow("A(src)",WINDOW_AUTOSIZE);
	imshow("A(src)", src);

	/****************/
	//构造函数创建一个Mat类
#if 1
	Mat src2(src.size(), src.type(), Scalar(0, 0, 255));//src2只是跟src一样的大小,一样的格式
	//或者不赋值像素值-->Mat src2(src.size(), src.type());
	namedWindow("Mat src2(src.size(), src.type())",WINDOW_AUTOSIZE);
	imshow("Mat src2(src.size(), src.type())",src2);
#elif 0
	Mat src2;
	src2 = Mat(src.size(), src.type(), Scalar(0, 0, 255));
	//或者不赋值像素值-->src2 = Mat(src.size(), src.type());
	namedWindow("src2 = Mat(src.size(), src.type());", WINDOW_AUTOSIZE);
	imshow("src2 = Mat(src.size(), src.type());", src2);
#elif 0
	Mat src2;
	src2.create(src.size(), src.type());
	src2 = Scalar(0,0,255);
	namedWindow("src2.create(src.size(), src.type());", WINDOW_AUTOSIZE);
	imshow("src2.create(src.size(), src.type());", src2);
#endif
	//将src图像反转回来
	Mat savesrc(src);
	for (int rows = 0; rows < height; rows++)
		for (int cols = 0; cols <weight; cols++)
		{
			int b = savesrc.at<Vec3b>(rows, cols)[0];
			int g = savesrc.at<Vec3b>(rows, cols)[1];
			int r = savesrc.at<Vec3b>(rows, cols)[2];
			savesrc.at<Vec3b>(rows, cols)[0] = 255 - b;//反转
			savesrc.at<Vec3b>(rows, cols)[1] = 255 - g;
			savesrc.at<Vec3b>(rows, cols)[2] = 255 - r;
		}
	namedWindow("Mat savesrc(src);", WINDOW_AUTOSIZE);
	imshow("Mat savesrc(src);", savesrc);


	//另一种将RGB图像转化为GRAY图像
	Mat GraySrc(src.size(), CV_8UC1);
	for (int rows = 0; rows < height; rows++)
		for (int cols = 0; cols <weight; cols++)
		{
			int b = src.at<Vec3b>(rows, cols)[0];
			int g = src.at<Vec3b>(rows, cols)[1];
			int r = src.at<Vec3b>(rows, cols)[2];
			GraySrc.at<uchar>(rows, cols) = max(r,max(b,g));
			//GraySrc.at<uchar>(rows, cols) = min(r, min(b, g));
		}
	namedWindow("GraySrc.at<uchar>(rows, cols) = max(r,max(b,g));", WINDOW_AUTOSIZE);
	imshow("GraySrc.at<uchar>(rows, cols) = max(r,max(b,g));", GraySrc);

	//eye 
	Mat eyeeye = Mat::eye(3,3,CV_8UC1);
	//eyeeye = Scalar(0);
	cout << "eyeeye = " << eyeeye << endl;
	//system("Pause");  opencv3用这个的话,imshow不了图片

	waitKey(0);
	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

玖零猴

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值