您的位置:首页 > 运维架构

opencv学习笔记 二 操作像素

2017-09-24 22:05 351 查看
第二章: 操作像素

2.1引言:

灰度图像像素由8位无符号数来表示,0表示黑色,255表示白色。

彩色图像(RGB)像素由三个8位的无符号数来表示,存储方式为三元数(B,G,R)

2.2存取像素值

Mat类有若干成员和成员函数来获取图像的属性:

成员cols和rows表示 宽和高(列和行)

成员函数 at<像素类型名称>(int i, int j)可以用来存取像素

image.at<uchar>(i,j); //灰度图像的像素,at后的数据类型一定要和image像素数据类型吻合

image.at<Vec3b>(i,j); //RGB图像的像素 Vec3b表示三个8位无符号整形组成的向量

image.at<Vec3b>(i,j)[channel]; //像素向量的第channel个元素

image.at<Vec3b>(i,j)[1]; //第二个

image.at<Vec3b>(i,j)[2]; //第三个

int Mat::channels(); //用来获得像素的通道数

cv::Mat_类可以更方便访问像素

cv::Mat_<uchar> image1=image; //用Mat_类定义带数据类型的图像数据,可以直接访问像素

image1(i,j) = 0;

2.3使用指针来遍历图像

uchar *data = image.ptr<uchar>(j); //获取第i行的指针

data[i] = 0; //表示第i行,第j列元素值置0,而不是第i行第j列像素置0(RGB图像每个像素有三个元素)

颜色缩减函数:

#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <iostream>
using namespace cv;
using namespace std;
void colorReduce(Mat &image, int div)
{
int n1 = image.rows;
int nc = image.cols*image.channels();
for (int i = 0;i < n1;i++)
{
uchar *data = image.ptr<uchar>(i);
for (int j = 0;j < nc;j++)
{
data[j] = data[j] / div *div + div / 2;
}
}
}
int main(int argc, char** argv)
{
Mat image = imread("D:/1.jpg", 1);
namedWindow("picture");
imshow("picture", image);
colorReduce(image, 10);
namedWindow("key");
imshow("key", image);
waitKey(0);
return 0;
}
image.step //表示行的字节数image.element//表示像素的字节数颜色缩减:

div = pow(2,n);

uchar mask = 0xFF<<n;

data[i] = (data[i]&mask)+div/2;

上个颜色缩减函数中,改变原图像数据,若不想修改原图像则可以用:image.copyTo(image1);或者:void reducecolor(const Mat &image, Mat &result, int div){result.creat(image.rows, image.cols, image.type());……}//检查result和image大小数据类型是否一致

高效遍历图像:

void colorReduce(Mat &image, int div)
{
int n1 = image.rows;
int nc = image.cols*image.channels();
//image.isContinuous()判断image是否有额外的填补
//返回值为真,则image没有进行额外的填补,即图像在内存中是连续存储的;
//可以用一层循环来实现;这种方式在处理若干个小图像有优势
if (image.isContinuous())
{
nc = image.cols*image.cols;
n1 = 1;
//image.reshape(1, image.cols*image.rows); 也可以用这个
}
for (int i = 0;i < n1;i++)
{
uchar *data = image.ptr<uchar>(i);
for (int j = 0;j < nc;j++)
{
data[j] = data[j] / div *div + div / 2;
}
}
}


底层指针运算:
void colorReduce(Mat &image, int div)
{
int n1 = image.rows;
int nc = image.cols*image.channels();
uchar *data = image.data;//image.data可以用来获取当前内存块的首地址
for (int i = 0;i < n1;i++)
{
for(int j =0;j<nc;j++)
{
data[j] = data[j] / div *div + div / 2;
}
data+=image.step;//image.step表示每一行的宽度(包括补充值)
}
}


2.4使用迭代器遍历图像遍历器是一种特殊的类,专门用于遍历集合中的各个元素图像迭代器的声明:

Mat Iterator_<Vec3b> it ;

Mat_<Vec3b>::iterator;
void colorReduce(Mat &image, int div)
{
//cv::Mat iterator_<cv::Vec3b> it;//不好使
Mat_<Vec3b>::iterator it = image.begin<Vec3b>();
Mat_<Vec3b>::iterator itend = image.end<Vec3b>();
for (;it != itend;++it)//it加一,it调向下一个像素(非元素)
{
(*it)[0] = (*it)[0] / div*div + div / 2;
(*it)[1] = (*it)[1] / div*div + div / 2;
(*it)[2] = (*it)[2] / div*div + div / 2;
}
}


常量迭代器:当前不会对Mat类实例进行修改

Mat ConstIterator_<Vec3b> it ;

Mat_<Vec3b>::const_iterator;

2.5 编写高效的图像遍历循环

void colorReduce(Mat &image, int div)
{
int n1 = image.rows;
int nc = image.cols;
if (image.isContinuous())//分类效率高
{
nc *= n1;
n1 = 1;
}
int n = static_cast<int>(log(static_cast<double>(div)) / log(2.0));//位运算效率高
uchar mask = 0xFF << n;
for (int j = 0;j < n1;++j)
{
uchar *data = image.ptr<uchar>(j);
for (int i = 0;i < nc;++i)
{
*data++ = *data&mask + div / 2;
*data++ = *data&mask + div / 2;
*data++ = *data&mask + div / 2;
}
}
}


2.6 遍历图像和邻域操作锐化滤波器灰度图像:
void sharpen(const Mat &image, Mat &output)
{
output.create(image.size(), image.type());
for (int i = 1;i < image.rows - 1;++i)
{
const uchar *previous = image.ptr<uchar>(i-1);
const uchar *current = image.ptr<uchar>(i);
const uchar *next = image.ptr<uchar>(i+1);
uchar *result = output.ptr<uchar>(i);
for (int j = 1;j < image.cols-1;++j)
{
result[j] = saturate_cast<uchar>// saturate_cast<uchar>用于数据截断到0~255
(5 * current[j] - previous[j] - next[j] - current[j - 1] - current[j + 1]);
//*result++ = 5 * current[j] - previous[j] - next[j] - current[j - 1] - current[j + 1];
}
}
output.row(0).setTo(Scalar(0));//output.row(0)表示输出的第0行,setTo(Scalar(0)),置为0
output.row(output.rows-1).setTo(Scalar(0));
output.col(0).setTo(Scalar(0));
output.col(output.cols-1).setTo(Scalar(0));
}


彩色图像:
void sharpen3d(const Mat &image, Mat &output)
{
output.create(image.size(), image.type());
int nc = image.cols * 3;
for (int i = 1;i < image.rows - 1;++i)
{
const uchar *previous = image.ptr<uchar>(i-1);
const uchar *current = image.ptr<uchar>(i);
const uchar *next = image.ptr<uchar>(i+1);
uchar *result = output.ptr<uchar>(i);
for (int j = 3;j < nc-3;++j)//也可以使用迭代器
{
result[j] = saturate_cast<uchar>// saturate_cast<uchar>用于数据截断到0~255
(5 * current[j] - previous[j] - next[j] - current[j - 3] - current[j + 3]);
//*result++ = 5 * current[j] - previous[j] - next[j] - current[j - 1] - current[j + 1];
}
}
output.row(0).setTo(Scalar(0, 0, 0));//output.row(0)表示输出的第0行,setTo(Scalar(0)),置为0
output.row(output.rows-1).setTo(Scalar(0, 0, 0));
output.col(0).setTo(Scalar(0, 0, 0));
output.col(output.cols-1).setTo(Scalar(0, 0, 0));
}


filter2D滤波器首先定义Mat核矩阵

#include <opencv2/imgproc.hpp> //包含filter2D()函数
void sharpen2D(const Mat &image, Mat &output)
{
Mat kernel(3, 3, CV_32F, Scalar(0));//定义核矩阵
kernel.at<double>(0, 1) = -1;
kernel.at<double>(1, 0) = -1;
kernel.at<double>(1, 1) = 5;
kernel.at<double>(2, 1) = -1;
kernel.at<double>(1, 2) = -1;
filter2D(image, output, image.depth, kernel);
}

2.7进行简单的图像算数

void addWeighted(InputArray src1, double alpha, InputArray src2,

                              double beta, double gamma, OutputArray dst, int dtype = -1);

dst = src1*alpha + scr*beta + gamma//(按输入的原格式返回)

add(imageA, imageB, imageC); //imageC = imageA + imageB//(A和B的大小应该相同)

add(imageA, scalar(k), imageC); //imageC = imageA + k

scaleAdd(imageA, k, imageB, imageC); //imageC = imageA*k +imageB

m1*m2 //矩阵乘法

m1.inv() //矩阵求逆

m1.t() //矩阵求转置

2.8 定义感兴趣的区域(ROI)添加logo

Mat image = imread("D:/1.jpg", 0);

imshow("picture原图", image);

Mat logo = imread("D
94ea
:/2.jpg", 0);

Mat imageROI;

logo = logo(Rect(0, 0, 400,200));

imshow("picturelogo", logo);

imageROI = image(Rect(0, 0, logo.cols, logo.rows));

addWeighted(imageROI, 0.5, logo, 0.5, 0.0, imageROI);

imshow("picture叠加", imageROI);

waitKey(0);

也可以通过图像掩膜完成定义ROI的方法:

imageROI = image(Rect(100, 100, 300, 300)); //选择顶点(100,100)宽度和长度分别为300,300

imageROI = image(range(100, 400), range(100,400)); //ROI与原始图像共享数据区

创建原始图像的特定行:

Mat imageROI = image.rowRange(start, end);

Mat imageROI = image.colRange(start, end);



























































































                                            
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: