【OpenCV】笔记(5)——图像类型和基本操作

图像类型
像素访问
图像基本操作
直方图



一. 基本数据类型

Mat 
一幅图像被保存为一个头加上包含像素数据的内存区

图像有若干通道,灰度图有一个通道,彩色图像通常有绿三个构成成分(OpenCV 以绿来存储这三个分量    )
此外还有第四个通道,及透明度(alpha)通道
用img.channels()来获取一幅img图像的通道数

每个像素使用若干位来存储,称之为图像深度(image depth)
对于灰度图像,像素通常存储为8位,因此允许256个(0~255)个灰度级

对于彩色图像,每个像素存储为3个字节,每个颜色通道占一个字节

某些操作必须以浮点格式存储像素

可以使用img.depth()来获取图像深度,返回值是:
CV_8U          //8位无符号整数(0~255)
CV_8S          //8位有符号整数(-128~127)
CV_16U          //16位无符号整数(0~65535)
CV_16S          //16位有符号整数(-32768~32767)
CV_32S          //32位有符号整数(-2147483684~2147483647)
CV_32F          //32位浮点数
CV_64F          //64位浮点数

使用convertTo( )可以将一种图像深度转换成另外一种图像深度


Mat img=imread("cumt.png",IMREAD_GRAYSCALE);
Mat fp;
img.covertTo(fp,CV_32F);





二.  像素级访问
方法:
     
at<>
必须指定矩阵单元的类型

                //As for gray image
                Matsrc1 = imread("lena.jpg",IMREAD_GRAYSCALE);
                ucharpixel1= src1.at<uchar>(0, 0);
                cout<<"Value of pixell(0,0) is:"<<(unsignedint)pixel1<<endl;
                
                //As for colorful image
                Matsrc2 = imread("lena.jpg",IMREAD_COLOR);
                Vec3bpixel2 = src2.at<Vec3b>(0, 0);
                cout<<"B component of pixel (0,0) is:"<<(unsignedint)pixel2[0]<<endl;
                
                 //将浮点矩阵初始化为PI
                 MatM(200, 200,CV_64F);
                for(int  i = 0; i < M.rows; i++)
                {
                                for(intj = 0; j < M.cols; j++)
                                {
                                                M.at<double>(i, j) =CV_PI;
                                }
                }

简单但是费时
ptr函数
返回指向图像特定行的指针
                //To attain every pixel's R, G, B
                ucharR, G, B;
                for(inti=0;i<src2.rows;i++)
                {
                                Vec3b* pixrow = src2.ptr<Vec3b>(i);
                                for(intj = 0;j < src2.cols;j++)
                                {
                                                B = pixrow[j][0];
                                                G = pixrow[j][1];
                                                R = pixrow[j][2];
                                }
                }
 







测量时间

getTickCount()
getTickFrequencY()

                //Time measuring
                doublet0 = (double)getTickCount();

                doubleelapsed = ((double)getTickCount() - t0) / getTickFrequency();//单位为秒




常用操作


操作
代码示例
设置矩阵的值
                img.setTo(0);//对于一个通道的图像
                img.setTo(Scalar(B, G, R));//对于三通道的图像
MATLAB风格的矩阵初始化
                Matm1 =Mat::eye(m, n,CV_64F);//m*n阶单位矩阵
                Matm2 =Mat::zeros(m, n,CV_8UC1);//m*n阶全0矩阵
                Matm3 =Mat::ones(m, n,CV_68UC1)*255;//m*n阶全1矩阵
随机初始化
                Matm4 =Mat(100, 100,CV_8UC1);
                randu(m4, 0, 255);
创建矩阵的一个副本
                Matimg1 = img.clone();
创建一个(具有掩码)矩阵的副本
                img.copy(img1, mask);
引用一个子矩阵(不复制数据)
                Matimg2 = img(Range(start1, end1),Range(start2, end2));
图像裁剪
                Rectroi(r1, c2, width, height);
                Matimg5 = img(roi).clone();//数据拷贝
调整图像大小
                resize(img, img1,Size(), 0.5, 0.5);//将图像变为原来的1/2
翻转图像

                flip(imgsrc, imgdst, code);
                //code=0 =>垂直翻转
                //code>0 =>水平翻转
                //code<0 =>垂直和水平翻转
分割通道
                Matchannel[3];
                split(img, channel);
                imshow("B", channel[0]);//显示蓝色
合并通道
                merge(channel, img);
计算非零像素数
                intnz = countNonZero(img);
最小值和最大值
                doublem, M;
                PointmLoc, MLoc;
                minMaxLoc(img, &m, &M, &mLoc, &MLoc);
像素值均值
                Scalarm, stdd;
                meanStdDev(img, m, stdd);
                uintmean_pxl = mean.val[0];
检查图像数据是否为空
                if(img.empty())
                                cout<<"Could not load image.";



算数运算
位运算
                bitwise_and();
                bitwise_not();
                bitwise_or();
                bitwise_xor();

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

usingnamespacestd;
usingnamespacecv;

intmain()
{
                /*
                *用bitwise_and()进行图像的剪裁
                *
                */
                Matimg1 = imread("lena.png",IMREAD_GRAYSCALE);
                if(img1.empty())
                {
                                cout<<"Error, cannot load image!"<<endl;

                }
                imshow("Original", img1);

                //创建掩码图像
                Matmask(img1.rows, img1.cols,CV_8UC1,Scalar(0, 0, 0));
                circle(mask,Point(img1.rows / 2, img1.cols / 2), 150, 255, -1);
                imshow("Mask", mask);

                //执行AND运算
                Matr;
                bitwise_and(img1, mask, r);

                //使用白色填充外部
                constucharwhite = 255;
                for(inti = 0;i < r.rows;i++)
                                for(intj = 0;j < r.cols;j++)
                                                if(!mask.at<uchar>(i, j))
                                                                r.at<uchar>(i, j) = white;
                imshow("Result", r);

                waitKey();

                return0;
}








应用2用来 估计PI的值
                /*
                *示例二
                *用bitwise_and()对PI的值进行估计
                *
                */
                constintside = 200;
                constintnpixels = 600000;

                inti, j;
                Mats1 =Mat::zeros(side, side,CV_8UC1);
                Mats2 = s1.clone();
                circle(s1,Point(side / 2, side / 2), side / 2, 255, -1);

                imshow("s1", s1);

                for(intk=0;k<npixels;k++)
                {
                                i = rand() % side;
                                j = rand() % side;
                                s2.at<uchar>(i, j) = 255;

                }

                imshow("s2", s2);

                Matr;
                bitwise_and(s1, s2, r);
                imshow("r", r);

                intAcircle = countNonZero(r);
                intAsquare = countNonZero(s2);
                floatPi = 4 * (float)Acircle / Asquare;
                cout<<"Estimated value of Pi is:"<<fixed<<setprecision(6)<<Pi<<endl;

                waitKey();

                return0;
}





数据持久化

OpenCV中除了读取、写入图像和视频特定的函数之外,还有一种更加通用的方式来保存和加载数据,这种方法称之为数据持久化(data persistence):程序中对象和变量的值被记录(序列化)在磁盘上。
主类是aptly,命名是FilleStorage,表示磁盘上一个文件。实际上,数据被储存为XML,或者YAML格式。

写入数据时的步骤:
1     调用构造函数FileStorage,使用FileStorage::WRITE值传递一个文件名称和一个标志,数据格式则是由文件扩展名(即:.xml,.yml或.yaml)定义的;
2     使用运算符<<将数据写入文件,数据通常被写为字符串值对;
3     使用release方法关闭文件

读取数据时需要如下步骤:
1     调用构造函数FileStorage,使用FileStorage::READ值床底一个文件名和一个标志;
2     使用运算符>>或者[ ]从文件中读取数据
3     使用release方法关闭文件

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

usingnamespacestd;
usingnamespacecv;

Matimg1;

voidtb1_Callback(intvalue,void*)
{
                Mattemp = img1+value;
                imshow("main_win", temp);
}

intmain()
{
                img1=imread("girl.png",IMREAD_GRAYSCALE);

                if(img1.empty())
                {
                                cout<<"Error! Cannot load image!"<<endl;

                }

                inttb1_value = 0;

                //加载滑动条的值
                FileStorage  fs1("config.xml",FileStorage::READ);
                tb1_value = fs1["tb1_value"];//读取数据tb1_value的方法1
                //fs1["tb1_value"]>>tb1_value ;//读取数据tb1_value的方法2
                fs1.release();

                //创建滑动条
                namedWindow("main_win");
                createTrackbar("brightness","main_win", &tb1_value, 255, tb1_Callback);
                tb1_Callback(tb1_value,NULL);

                waitKey();

                //退出时保存滑动条的值
                FileStoragefs2("config.xml",FileStorage::WRITE);
                fs2<<"tb1_value"<<tb1_value;
                fs2.release();

                return0;

}




图像遍历


#include <opencv.hpp>
#include <opencv2/opencv.hpp>
#include <opencv/highgui.h>
#include <iostream>

using namespace std;
using namespace cv;
/*
* To reduce the color of R,G,B
* @param src 
* @param dst
* @param div how many parts should we divide the color space to
*/


void reduceColor(Mat src, Mat &dst,int div)
{
	for (int i = 0;i < src.rows;i++)
	{
		for (int j = 0; j < src.cols; j++)
		{
			cout << "shame!-----------\n";
			dst.at<Vec3b>(i, j)[0] = src.at<Vec3b>(i, j)[0] / div*div + div / 2;
			dst.at<Vec3b>(i, j)[1] = src.at<Vec3b>(i, j)[1] / div*div + div / 2;
			dst.at<Vec3b>(i, j)[2] = src.at<Vec3b>(i, j)[2] / div*div + div / 2;
		}
	}

}

int main()
{
	int div=64;
	//read the souce image
	Mat src;
	src=imread("dog2.png");
	namedWindow("Original", WINDOW_AUTOSIZE);
	imshow("Original", src);

	
	//reduce color
	Mat rdc_img;
	reduceColor(src, rdc_img, div);

	//show
	namedWindow("Reduced color image", WINDOW_AUTOSIZE);
	imshow("Reduced color image", rdc_img);
	
	waitKey();

	return 0;
}





评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值