opencv2 入门 像素的读写操作

typedef unsigned char uchar
在这里插入图片描述

#include "opencv2/opencv.hpp"
#include <iostream>

using namespace std;
using namespace cv;

int main()
{
	Mat pImg = imread("D:\\cpp_practice\\lenna.tif",0);
	//1:IMREAD_COLOR;0:IMREAD_GRAYSCALE; -1 IMREAD_UNCHANGED
	//Mat 多是浅拷贝 uchar* data 指向数据区,
	Rect rect(180, 200, 222, 200);
	// 矩形框x  y width height
	Mat roi = Mat(pImg, rect);
	Mat pImagRect = pImg.clone(); //deep copy mat.copyto

	rectangle(pImagRect, rect, Scalar(0, 255, 0),2);
	//是一个函数;将pImagRect 添加矩形框,颜色为绿,2代表 linethickness
	//void rectangle(Mat& img, Point pt1,Point pt2,const Scalar& color, int thickness=1, int lineType=8, int shift=0)
	//void rectangle(Mat& img, Rect rec, const Scalar& color, int thickness = 1, int lineType = 8, int shift = 0)
	cv::imshow("Original image with rectange", pImagRect);
	cout << roi << endl;
	imshow("roi",roi);

	waitKey();

}

像素值得读写
方法1:Mat.at<data_type>(,)

#include "opencv2/opencv.hpp"
#include <iostream>

using namespace std;
using namespace cv;

int main()
{
	Mat grayim(600, 800, CV_8UC1);
	Mat colorim(600, 800, CV_8UC3);
	
	for (int i = 0; i < grayim.rows; ++i)
	{
		for (int j = 0; j < grayim.cols; ++j)
			grayim.at<uchar>(i, j) = (i + j) % 255;
	}
	imshow("gray1", grayim);

	for (int i = 0; i < colorim.rows;++i)
	{
		for (int j = 0;j < colorim.cols; ++j)
		{
			Vec3b pixel;
			pixel[0] = i % 255;
			pixel[1] = j % 255;
			pixel[2] = 0;
			colorim.at<Vec3b>(i, j) = pixel; //typedef cv::Vec<uchar,3> cv::Vec3b
		}
	}
	imshow("colorim", colorim);
	waitKey();

}

像素值的读写2:迭代器

#include "opencv2/opencv.hpp"
#include <iostream>

using namespace std;
using namespace cv;

int main()
{
	Mat grayim(600, 800, CV_8UC1);
	Mat colorim(600, 800, CV_8UC3);
	
	MatIterator_<uchar> grayit, grayend;
	for (grayit = grayim.begin<uchar>(),grayend = grayim.end<uchar>();grayit != grayend; ++grayit)
	{
		*grayit = rand() % 255;
	}
	imshow("gray1", grayim);
	MatIterator_<Vec3b> colorit, colorend;
	for (colorit = colorim.begin<Vec3b>(),colorend = colorim.end<Vec3b>();colorit != colorend;++colorit)
	{
		
			(*colorit)[0] = rand() % 255;
			(*colorit)[1] = rand() % 255;
			(*colorit)[2] = 0;
		
	}
	imshow("colorim", colorim);
	waitKey();

}

像素值的读写3——指针

#include "opencv2/opencv.hpp"
#include <iostream>

using namespace std;
using namespace cv;

int main()
{
	Mat grayim(600, 800, CV_8UC1);
	
	for (int i = 0; i < grayim.rows; ++i)
	{
		//获取第i行首像素的指针
		uchar *p = grayim.ptr<uchar>(i);
		for (int j = 0; j < grayim.cols;++j)
		{
			p[j] = (i + j) % 255;
		}
	}
	imshow("gray1", grayim);
	waitKey();

}

scalar 标量

typedef struct Scalar
{
    double val[4];
}Scalar;
#include "opencv2/opencv.hpp"
#include <iostream>

using namespace std;
using namespace cv;

void scalar_demo1() {
	Mat M(4, 4, CV_32FC2, Scalar(1, 3));
	cout << M << endl;
}
void scalar_demo2() {
	Mat M(4, 4, CV_32FC3, Scalar(1, 2, 3));
	cout << M << endl;
}
//C2  是不能用imshow显示的,只能134
void scalar_demo3() {
	Mat M(4, 4, CV_32FC4, Scalar(1, 2, 3));
	cout << M << endl;
}
int main()
{

	
	
		//resize_img();
		//convert_color_space();
		scalar_demo1();
		cout << "**********************************" << endl;
		scalar_demo2();
		cout << "**********************************" << endl;
		scalar_demo3();

		waitKey();
		return 0;
}
[1, 3, 1, 3, 1, 3, 1, 3;
 1, 3, 1, 3, 1, 3, 1, 3;
 1, 3, 1, 3, 1, 3, 1, 3;
 1, 3, 1, 3, 1, 3, 1, 3]
**********************************
[1, 2, 3, 1, 2, 3, 1, 2, 3, 1, 2, 3;
 1, 2, 3, 1, 2, 3, 1, 2, 3, 1, 2, 3;
 1, 2, 3, 1, 2, 3, 1, 2, 3, 1, 2, 3;
 1, 2, 3, 1, 2, 3, 1, 2, 3, 1, 2, 3]
**********************************
[1, 2, 3, 0, 1, 2, 3, 0, 1, 2, 3, 0, 1, 2, 3, 0;
 1, 2, 3, 0, 1, 2, 3, 0, 1, 2, 3, 0, 1, 2, 3, 0;
 1, 2, 3, 0, 1, 2, 3, 0, 1, 2, 3, 0, 1, 2, 3, 0;
 1, 2, 3, 0, 1, 2, 3, 0, 1, 2, 3, 0, 1, 2, 3, 0]

Mat.step[]

#include "opencv2/opencv.hpp"
#include <iostream>

using namespace std;
using namespace cv;

int main()
{
	Mat m(480, 320, CV_8U,Scalar(125));
	Mat m2(480, 320, CV_8UC2, Scalar(125,255));
	Mat m3(480, 320, CV_8UC3, Scalar(125,255,0));
	cout << m.step[0] << "channel1__  " << m.step[1] << " elementsize " << m.elemSize() << "elementSize1 " << m.elemSize1() << endl;
	cout << m2.step[0] << "channel2__  " << m2.step[1] << " elementsize " << m2.elemSize() << "elementSize1 " << m2.elemSize1() << endl;
	cout << m3.step[0] << "channel3__  " << m3.step[1] << " elementsize " << m3.elemSize() << "elementSize1 " << m3.elemSize1() << endl;
		
	cout << m.step1() <<  "   " << m.step1(1) <<  endl;
	cout << m2.step1() << "   " << m.step1(1) << endl;
	cout << m3.step1() << "   " << m.step1(1) << endl;
		
	waitKey();
	return 0;
}
320channel1__  1 elementsize 1elementSize1 1
640channel2__  2 elementsize 2elementSize1 1
960channel3__  3 elementsize 3elementSize1 1
320   1
640   1
960   1

depth
矩阵中元素的一个通道的数据类型,这个值和type是相关的。例如 type为 CV_16SC2,一个2通道的16位的有符号整数。那么,depth则是CV_16S。depth也是一系列的预定义值,
将type的预定义值去掉通道信息就是depth值:
CV_8U CV_8S CV_16U CV_16S CV_32S CV_32F CV_64F
elemSize
矩阵一个元素占用的字节数,例如:type是CV_16SC3,那么elemSize = 3 * 16 / 8 = 6 bytes
elemSize1
矩阵元素一个通道占用的字节数,例如:type是CV_16CS3,那么elemSize1 = 16 / 8 = 2 bytes = elemSize / channels
这里写图片描述
step这里指出的是图像在各个梯级上的字节数大小,而这里的梯级指的是构成图像的名层次。
上图三维图像由一个一个名面(第一级)构成,每一个平面由一行一行(第二级)构成,每行由一个一个点(第三级)构成。
同理:二维图像由一行一行(第一级)构成,而每一行又由一个一个点(第二级)构成。
Mat中的step[0]就是我们每一个第一级,在内存中占据的字节数量。例如,二维图像中step[0]就是每一行(第一级)在矩阵内存中,占据的字节的数量。也就是说step[i]就是第i+1级在矩阵内存中占据的字节的数量。

#include "opencv2/opencv.hpp"
#include <iostream>

using namespace std;
using namespace cv;

int main()
{
	Mat m(400, 400, CV_8U,Scalar(0));
	for (int col = 0; col < 400; col++)
	{
		for (int row = 195; row < 205; row++)
		{
			cout << (int)(*(m.data + m.step[0] * row + m.step[1] * col)) << "==>";
			*(m.data + m.step[0] * row + m.step[1] * col) = 255;
			cout << (int)(*(m.data + m.step[0] * row + m.step[1] * col)) << endl;
		}
	}
	imshow("---", m);
	waitKey();
	return 0;
}


降低灰度级

#include "opencv2/opencv.hpp"
#include <iostream>

using namespace std;
using namespace cv;

int main()
{
	//降低灰度级,使用灰度查找表
	int dividewith = 10;
	uchar  table[256];
	for (int i = 0;i < 256;i++)
	{
		table[i] = dividewith * (i / dividewith);
	}

	Mat lookuptable(1, 256, CV_8U);
	uchar *p = lookuptable.data;
	for (int j = 0; j < 256; ++j)
	{
		p[j] = table[j];
	}

	//imshow("---", lookuptable);
	Mat m = imread("D:\\cpp_practice\\lenna.tif");
	cout << m.type() << endl << m.TYPE_MASK << endl;    //16    4095?
	Mat m_out;
	LUT(m, lookuptable, m_out);
	imshow("Origin input", m);
	imshow("Output", m_out);
	waitKey();
	return 0;
}

颜色空间转化 color2gray

#include "opencv2/opencv.hpp"
#include <iostream>

using namespace std;
using namespace cv;

int main()
{
	Mat m = imread("D:\\cpp_practice\\lenna.tif");
	
	if (m.empty())
	{
		cout << "image error" << endl;
		return -1;
	}

	Mat bgr2gray , rgb2gray;
	////采用CV_BGR2GRAY,转换公式Gray = 0.1140*B + 0.5870*G + 0.2989*R
	cvtColor(m, bgr2gray, CV_BGR2GRAY);
	//采用CV_RGB2GRAY,转换公式Gray = 0.1140*R + 0.5870*G + 0.2989*B
	cvtColor(m, rgb2gray, CV_RGB2GRAY);

	// 采用CV_GRAY2BGR, 转换公式B = G = R = Gray
	cv::Mat gray2bgrImg;
	cvtColor(bgr2gray, gray2bgrImg, CV_GRAY2BGR);

	//采用CV_GRAY2RGB,转换公式R = G = B = Gray
	cv::Mat gray2rgbImg;
	cvtColor(rgb2gray, gray2rgbImg, CV_GRAY2RGB);

	cout << "origin 1st " << m.at<Vec3b>(5, 5)[0] << "2nd " << m.at<Vec3b>(5, 5)[1] << "3rd" << m.at<Vec3b>(5, 5)[2] << endl;
	cout << "origin 1st " << bgr2gray.at<uchar>(5, 5);
	cout << "origin 1st " << rgb2gray.at<Vec3b>(5, 5)[0] << "2nd " << rgb2gray.at<Vec3b>(5, 5)[1] << "3rd" << rgb2gray.at<Vec3b>(5, 5)[2] << endl;

	waitKey();
	return 0;
}

绘制灰度直方图calcHist()

void calcHist(const Mat* arrays, intnarrays, const int* channels, InputArray mask, OutputArray 
hist, int dims,const int* histSize, const float** ranges, bool uniform=true, boolaccumulate=false );

参数解释:

arrays:输入的图像的指针,可以是多幅图像,所有的图像必须有同样的深度(CV_8U orCV_32F)。同时一副图像可以有多个channes。
narrays:输入的图像的个数。
channels:用来计算直方图的channes的数组。比如输入是2副图像,第一副图像有0,1,2共三个channel,第二幅图像只有0一个channel,那么输入就一共有4个channes,如果int channels[3] = {3, 2, 0},那么就表示是使用第二副图像的第一个通道和第一副图像的第2和第0个通道来计算直方图。
mask:掩码。如果mask不为空,那么它必须是一个8位(CV_8U)的数组,并且它的大小的和arrays[i]的大小相同,值为1的点将用来计算直方图。
hist:计算出来的直方图
dims:计算出来的直方图的维数。
histSize:在每一维上直方图的个数。简单把直方图看作一个一个的竖条的话,就是每一维上竖条的个数。
ranges:用来进行统计的范围。比如 float rang1[] = {0, 20};float rang2[] = {30, 40}; const float*rangs[] = {rang1, rang2};那么就是对0,20和30,40范围的值进行统计。
uniform:每一个竖条的宽度是否相等。
accumulate: 是否累加。如果为true,在下次计算的时候不会首先清空hist。

#include "opencv2/opencv.hpp"
#include <iostream>

using namespace std;
using namespace cv;

int main()
{
		Mat srcImage = imread("D:\\cpp_practice\\lena_gray.tif");
		imshow("原图", srcImage);
		if (!srcImage.data)
		{
			cout << "fail to load image" << endl;
			return 0;
		}

		MatND dstHist;//得到的直方图     
		int dims = 1;//得到的直方图的维数 灰度图的维数为1
		float hranges[2] = { 0, 255 };
		const float *ranges[1] = { hranges };   // 这里需要为const类型,二维数组用来指出每个区间的范围  
		int size = 256;//直方图横坐标的区间数 即横坐标被分成256份
		int channels = 0;//图像得通道 灰度图的通道数为0
						 //计算图像的直方图  
		calcHist(&srcImage, 1, &channels, Mat(), dstHist, dims, &size, ranges);
		int scale = 1;
		Mat dstImage(size * scale, size, CV_8U, Scalar(0));
		//获取最大值和最小值  
		double minValue = 0;
		double maxValue = 0;
		minMaxLoc(dstHist, &minValue, &maxValue, 0, 0); //找到直方图中的最大值和最小值 
														//绘制出直方图  
		int hpt = saturate_cast<int>(0.9 * size);//防止溢出
		for (int i = 0; i < 256; i++)
		{
			float binValue = dstHist.at<float>(i);
			int realValue = saturate_cast<int>(binValue * hpt / maxValue);
			line(dstImage, Point(i*scale, size - 1), Point((i + 1)*scale - 1, size - realValue), Scalar(255));
		}
		imshow("一维直方图", dstImage);
		waitKey(0);
		return 0;
	}

	


猜你喜欢

转载自blog.csdn.net/qq_35508344/article/details/82388472