Mat----Opencv学习(c++实现)

本文介绍了OpenCV中的图像数字化处理,包括灰度和彩色图片的读取、Mat类元素的遍历、多通道处理、矩阵运算和图像展示。通过实例展示了如何使用Mat类的成员方法和指针进行内存访问以及基本的图像操作。

OpenCV--图像数字化

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

void showMat_Int(Mat e) {
	if (e.dims == 1) {
		for (int i = 0; i < e.total(); i++) {
			cout << e.at<int>(i) << ",";
		}
		cout << endl;
		return;
	}
	if (e.dims == 2) {
		for (int i = 0; i < e.rows; i++) {
			const int* ptr = e.ptr<int>(i);
			for (int j = 0; j < e.cols; j++) {
				cout << ptr[j] << ",";
			}
			cout << endl;
		}
	}
}
void showMat_Float(Mat e) {
	if (e.dims == 1) {
		for (int i = 0; i < e.total(); i++) {
			cout << e.at<float>(i) << ",";
		}
		cout << endl;
		return;
	}
	if (e.dims == 2) {
		for (int i = 0; i < e.rows; i++) {
			const float* ptr = e.ptr<float>(i);
			for (int j = 0; j < e.cols; j++) {
				cout << ptr[j] << ",";
			}
			cout << endl;
		}
	}
}
void showMat_Vec3i(Mat e) {
	for (int i = 0; i < e.rows; i++) {
		Vec3i* ptr = e.ptr<Vec3i>(i);
		for (int j = 0; j < e.cols; j++) {
			cout << ptr[j] << ",";
		}
		cout << endl;
	}
}
int show_img_G()//G为灰度图片
{	//导图
	Mat img = imread("D://Study//OpenCV算法精解代码//OpenCV测试图片//第3章//img.jpg", IMREAD_GRAYSCALE);
	//改动窗口名
	string winname = "原图";
	namedWindow(winname, WINDOW_AUTOSIZE);
	//显示图片
	imshow(winname, img);
	waitKey();
	return 0;
}
int show_img_C() {
	Mat img = imread("D://Study//OpenCV算法精解代码//OpenCV测试图片//第3章//img3.jpg", IMREAD_COLOR);
	imshow("BGR",img);
	vector<Mat> planes;
	split(img, planes);
	imshow("B", planes[0]);
	imshow("G", planes[1]);
	imshow("R", planes[2]);
	waitKey();
	return 0;
}

int main(int argc,char*argv[]) {
	Mat m = Mat::ones(2, 3, CV_32FC(1));
	cout << m.cols;//得到m的行数

	cout << m.rows;//得到m的列数

	cout << endl;
	for (int i = 0; i < m.rows; i++) {
		for (int j = 0; j < m.cols; j++) {
			cout << m.at<float>(i,j)<<" ";//矩阵的遍历,得到i,j位置的矩阵值用at函数
			//还可以利用point函数将i,j变成坐标的形式
			//cout<<m.at<float>(Point(i,j));(不知道意义在哪doge)
		}
		cout << endl;
	}
	cout << endl;
	cout << "m的面积为" << m.total() << endl;
	cout << "m的通道数为" << m.channels() << endl;//上面两个为成员方法
	cout << "m的维数为" << m.dims << endl;//维数为成员变量

	cout << "================================"<<endl;
	//mat类的数值是以连续的一行存在内存中的,在此可以利用ptr的到每一行的首元素的地址,以此遍历整个mat
	for (int r = 0; r < m.rows; r++) {
		const float * ptr = m.ptr<float>(r);//在用ptr函数时,数据类型必须和矩阵mat的类型一致,否则将无法打印
		for (int j = 0; j < m.cols; j++) {
			cout << ptr[j]<<",";
		}
		cout << endl;
	}
	//m.isContinuous()判断m是不是在内存中连续存储
	cout << endl << m.isContinuous() << endl;
	if (m.isContinuous()) {
		const float* ptr1 = m.ptr<float>(0);
		for (int i = 0; i < m.total(); i++) {
			cout << ptr1[i]<<",";
		}
	}
	cout << endl << "=====================" << endl;
	// 向量vec,直接理解为列向量;
	Vec<int, 4> vi(1, 2, 3, 4);
	//vec同样可以具有rows、cols,访问向量中的值可以利用[]或者()访问
	cout << vi.rows << endl;
	cout << vi.cols << endl;
	cout << vi[0];
	//Vec被Opencv重命名例如
	/*
	* typedef Vec<uchar,3>vec3b
	* typedef Vec<int,2>vec2i;
	*/
	cout << "===============多通道======" << endl;
	//前面的方法都是基于单通道,下面介绍多通道
	//1.建立多通道mat,形式:Mat(int rows,int cols,CV_32FC(n)),n就是通道数
	Mat mm = (Mat_<Vec3i>(2, 2) << Vec3i(1, 2, 3), Vec3i(4, 5, 6),
		Vec3i(7, 8, 9), Vec3i(10, 11, 12));
	//at函数,在此处将多通道的Mat看为一个特殊的二维数组,每个元素都是一个列向量
	cout << "以at方式遍历" << endl;
	for (int i = 0; i < mm.rows; i++) {
		for (int j = 0; j < mm.cols; j++) {
			cout << mm.at<Vec3i>(i, j) << ",";
		}
		cout << endl;
	}
	//ptr函数,同样的,多通道在内存中也是以一行存储;
	cout << "以ptr方式遍历" << endl;
	for (int i = 0; i < mm.rows; i++) {
		Vec3i* ptr = mm.ptr<Vec3i>(i);
		for (int j = 0; j < mm.cols; j++) {
			cout << ptr[j] << ",";
		}
		cout << endl;
	}
	//isContinuous()和ptr,同样的该函数是判断此矩阵是否在内存中连续,如果返回true,可以利用一层循环遍历
	if (mm.isContinuous()) {
		Vec3i* ptr = mm.ptr<Vec3i>(0);
		for (int i = 0; i < mm.total(); i++) {
			cout << ptr[i] << ",";
		}
	}
	cout << endl;
	cout << "==========================" << endl;
	//分离通道以及合并通道
	//以mm为例,该Mat可以利用split函数分离多通道放在vector容器中;
	vector<Mat> planes;
	split(mm, planes);
	
	for (int i = 0; i < planes.size(); i++) {
		cout << planes[i] << ",";
	}
	cout << endl << "=======================" << endl;
	//合并通道,利用merge函数可以将多个单通道函数合并为多通道
	Mat plane0 = (Mat_<int>(2, 2) << 1, 2, 3, 4);
	Mat plane1 = (Mat_<int>(2, 2) << 5, 6, 7, 8);
	Mat plane2 = (Mat_<int>(2, 2) << 9, 10, 11, 12);
	Mat planes1[] = { plane0,plane1,plane2 };
	Mat mat;
	merge(planes1, 3, mat);
	showMat_Vec3i(mat);
	cout << "=====================";
	//得到矩阵的某一部分值
	cout << "得到矩阵的某一部分值:" << endl;
	Mat matrix = (Mat_<int>(5, 5) << 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11
		, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25);
	//的到matrix的第二行和第三行
	Mat r_range = matrix.rowRange(Range(2, 4));
	//得到matrix的第二列和第三列
	Mat c_range = matrix.colRange(Range(2, 4));
	showMat_Int(r_range);
	cout << "=====================\n";
	showMat_Int(c_range);
	cout << "=====================\n";
	//该方法是引用了matrix的地址,若在c_range中修改数值,会导致matrix中的数值也会修改
	//若不想修改数值,我们要使用clone或者copyto方法,例如:
	Mat c_range_clone = matrix.colRange(Range(2, 4)).clone();
	showMat_Int(c_range_clone);	
	cout << "=====================\n";
	//如果我们想得到该矩阵中的某一块子矩阵,我们可以使用Rect类,形式如下
	//Rect(int x,int y,int width,int highe)或者Rect(int x,int y,Size size)或者Rect(point 1,point 2)
	Mat rect_mat = matrix(Rect(Point(1, 1), Point(3, 3)));
	showMat_Int(rect_mat);
	cout << "=====================\n";
	//矩阵加法,减法,点乘,点除,乘方,其他
	Mat src1 = (Mat_<int>(2, 3) << 1, 2, 3, 4, 5, 6);
	Mat src2 = (Mat_<int>(2, 3) << 7, 8, 9, 10, 11, 12);
	//"+"被opencv重载,可以直接使用在相同类型的矩阵中,数值会被数据类型限制,add方法则会自动转换数据类型,接下来只会介绍以方法类型的操作
	//值得注意的是,这些方法具备重载形式,不仅可以进行矩阵间运算,还可以进行矩阵和数值的运算
	Mat dst;
	add(src1, src2, dst, Mat(), CV_32S);
	showMat_Int(dst);
	cout << "=======================\n";
	//减法类似于加法
	Mat det1;
	subtract(src1, src2, det1, Mat(), CV_32S);
	showMat_Int(det1);
	cout << "=======================\n";
	//点乘和点除,系数scale为点除结果乘上scale
	Mat det2, det3;
	multiply(src1, src2, det2, 1, CV_32S);
	divide(src1, src2, det3, 1, CV_32S);
	//乘方,参考数学中的左行右列,直接使用“*”运算符即可,注意的是,双通道进行计算是将两个Mat当成复数矩阵
	//exp和log函数分别计算指数和对数,pow和sqrt分别计算幂指数和开平方
	cout << "==========================\n";
	//灰度图片数字化
	show_img_G();
	//彩色图片数字化
	show_img_C();
	return 0;
}

看看就好,反正是我自己记录的

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值