图像类型
像素访问
图像基本操作
直方图
一. 基本数据类型
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;
}