【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
                 Mat src1 = imread( "lena.jpg" , IMREAD_GRAYSCALE );
                 uchar pixel1= src1.at< uchar >(0, 0);
                cout << "Value of pixell(0,0) is:" << ( unsigned int )pixel1 << endl;
                
                 //As for colorful image
                 Mat src2 = imread( "lena.jpg" , IMREAD_COLOR );
                 Vec3b pixel2 = src2.at< Vec3b >(0, 0);
                cout << "B component of pixel (0,0) is:" << ( unsigned int )pixel2 [ 0 ] << endl;
                
                 //将浮点矩阵初始化为PI
                 Mat M(200, 200, CV_64F );
                 for ( int   i = 0; i < M.rows; i++)
                {
                                 for ( int j = 0; j < M.cols; j++)
                                {
                                                M.at< double >(i, j) = CV_PI ;
                                }
                }

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







测量时间

getTickCount()
getTickFrequencY()

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

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




常用操作


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

                flip(imgsrc, imgdst, code);
                 //code=0 =>垂直翻转
                 //code>0 =>水平翻转
                 //code<0 =>垂直和水平翻转
分割通道
                 Mat channel[3];
                split(img, channel);
                imshow( "B" , channel[0]); //显示蓝色
合并通道
                merge(channel, img);
计算非零像素数
                 int nz = countNonZero(img);
最小值和最大值
                 double m, M;
                 Point mLoc, MLoc;
                minMaxLoc(img, &m, &M, &mLoc, &MLoc);
像素值均值
                 Scalar m, stdd;
                meanStdDev(img, m, stdd);
                 uint mean_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的值进行估计
                *
                */
                 const int side = 200;
                 const int npixels = 600000;

                 int i, j;
                 Mat s1 = Mat ::zeros(side, side, CV_8UC1 );
                 Mat s2 = s1.clone();
                circle(s1, Point (side / 2, side / 2), side / 2, 255, -1);

                imshow( "s1" , s1);

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

                }

                imshow( "s2" , s2);

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

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

                waitKey();

                 return 0;
}





数据持久化

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;
}





  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
这是opencv svm图像分类的整个工程代码,在VS2010下打开即可。整个工程文件以及我的所有训练的图片存放在这里,需要的可以下载,自己在找训练图片写代码花了很多时间,下载完后自行解压,训练图片和测试图片可以从这免费下载http://download.csdn.net/detail/always2015/8944959,project data文件夹直接放在D盘就行,里面存放训练的图片和待测试图片,以及训练过程中生成的中间文件,现在这个下载object_classfication_end则是工程文件,我用的是vs2010打开即可,下面工程里有几个要注意的地方: 1、在这个模块中使用到了c++的boost库,但是在这里有一个版本的限制。这个模块的代码只能在boost版本1.46以上使用,这个版本以下的就不能用了,直接运行就会出错,这是最需要注意的。因为在1.46版本以上中对比CsSVM这个类一些成员函数做了一些私有化的修改,所以在使用该类初始化对象时候需要注意。 2、我的模块所使用到的函数和产生的中间结果都是在一个categorizer类中声明的,由于不同的执行阶段中间结果有很多个,例如:训练图片聚类后所得到单词表矩阵,svm分类器的训练的结果等,中间结果的产生是相当耗时的,所以在刚开始就考虑到第一次运行时候把他以文件XML的格式保存下来,下次使用到的时候在读取。将一个矩阵存入文本的时候可以直接用输出流的方式将一个矩阵存入,但是读取时候如果用输入流直接一个矩阵变量的形式读取,那就肯定报错,因为输入流不支持直接对矩阵的操作,所以这时候只能对矩阵的元素一个一个进行读取了。 3、在测试的时候,如果输入的图片太小,或者全为黑色,当经过特征提取和单词构造完成使用svm进行分类时候会出现错误。经过调试代码,发现上述图片在生成该图片的单词的时候所得到的单词矩阵会是一个空矩阵,即该矩阵的行列数都为0,所以在使用svm分类器时候就出错。所以在使用每个输入图片的单词矩阵的时候先做一个判断,如果该矩阵行列数都为0,那么该图片直接跳过。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值