目录
- 获取像素指针
- 像素指针
- 目的
- API
- 像素范围处理
- API
- 掩膜操作
- 公式
- 作用
- API
- 代码演示
- 效果
获取像素指针
像素指针
二维图像保存在电脑中,大家可以理解为矩阵,一个二维数组,每个位置都会有一个像素值。
访问像素值,就是访问二维数组中某个位置的值。
目的
获取到像素点,我们就可以对这个像素点进行操作,如果我们加上循环嵌套,还可以遍历所有的像素点,即对所有的像素点进行操作。
API
Mat.ptr<uchar>(int i=0) //获取像素矩阵的指针,索引i表示第几行,从0开始计行数。
访问的时候,我们先访问行,后访问列,通过如下方式,我们获取行指针,索引i表示第几行,从0开始计行数。
例:
cv::Mat image = cv::Mat(400, 600, CV_8UC1); //宽400,长600
uchar * data00 = image.ptr<uchar>(0);
uchar * data10 = image.ptr<uchar>(1);
uchar * data01 = image.ptr<uchar>(0)[1];
- 定义了一个Mat变量image。
- data00是指向image第一行第一个元素的指针。
- data10是指向image第二行第一个元素的指针。
- data01是指向image第一行第二个元素的指针。
像素范围处理
我们在设置图像像素的灰度值或者RGB值时候,如果不了解,会随意设置,以RGB为例,他们的取值范围是从0 到255,所以如果我们输入范围以外的数据,为防止程序出错,我们需要控制范围,保证我们输入非法数据时候,不会导致程序出现问题。
处理的原则如下:
- 如果我们输入小于0的值,它会返回0,
- 如果我们输入大于255的值,它会返回255,
- 如果我们输入0-255之间的值,它会正常返回。
API
saturate_cast:
saturate_cast<uchar>(-100) //返回 0
saturate_cast<uchar>(288) //返回255
saturate_cast<uchar>(100) //返回100
掩膜操作
红色是中心像素,从上到下,从左到右对每个像素做同样的处理操作,得到最终结果就是对比度提高之后的输出图像Mat对象
由于是3 x 3,所以图像最边上一圈扫不到
对于外层一圈,不同算法不同,有的算法是将最外层全部设为0,有的是设为与其距离最近的像素点一致,有的是在原图外层加一层,这样经过掩膜的图像就是与原图一样尺寸了。
公式
作用
掩膜操作实现图像对比度调整。
API
filter2D
void filter2D(
InputArray src,
OutputArray dst,
int ddepth,
InputArray kernel,
Point anchor = Point(-1,-1),
double delta = 0,
int borderType = BORDER_DEFAULT
);
- (1)InputArray类型的src ,输入图像。
- (2)OutputArray类型的dst ,输出图像,图像的大小、通道数和输入图像相同。
- (3)int类型的ddepth,目标图像的所需深度。
若不设置或写-1,则生成和图像相同深度的图像 - (4)InputArray类型的kernel,卷积核(或者更确切地说是相关核)是一种单通道浮点矩阵;
如果要将不同的核应用于不同的通道,请使用split将图像分割成不同的颜色平面,并分别对其进行处理。 - (5)Point类型的anchor,表示锚点(即被平滑的那个点),注意他有默认值Point(-1,-1)。
如果这个点坐标是负值的话,就表示取核的中心为锚点,所以默认值Point(-1,-1)表示这个锚点在核的中心。 - (6)double类型的delta,在将筛选的像素存储到dst中之前添加到这些像素的可选值。说的有点专业了其实就是给所选的像素值添加一个值delta。
- (7)int类型的borderType,用于推断图像外部像素的某种边界模式。有默认值BORDER_DEFAULT。
例
filter2D( src, dst, src.depth(), kernel );
代码演示
#include <opencv2/opencv.hpp>
#include <iostream>
#include <math.h>
using namespace cv;
int main()
{
Mat src, dst;
src = imread("C:/Users/86176/Pictures/pics/lena(1).tiff");
if (!src.data) {
printf("could not load image...\n");
return -1;
}
namedWindow("input img", CV_WINDOW_AUTOSIZE);
imshow("input img", src);
/*
int cols = (src.cols - 1) * src.channels();//图像列 * 通道——每行中每个地址占了三个像素,那么原来的列就要x3
int rows = src.rows;
int offsetx = src.channels();
//rgb图像就有三个通道
//可以理解为,列不变,若是rgb图像,每一行中的一格就有三个
//也可以理解为,行不变,每一列中的每个点有三个
dst = Mat::zeros(src.size(), src.type());//将所有像素变为0—黑色
for (int row = 1; row < (rows - 1); row++) {
const uchar* previous = src.ptr<uchar>(row - 1);//上一行
const uchar* current = src.ptr<uchar>(row);//当前行
const uchar* next = src.ptr<uchar>(row + 1);//下一行
uchar* output = dst.ptr<uchar>(row);//指向处理后的图像
for (int col = offsetx; col < cols; col++) {
output[col] = saturate_cast<uchar>(5 * current[col] - (current[col - offsetx] + current[col + offsetx] + previous[col] + next[col]));
//每行中的单个地址有三个像素,所以列要x3
}
}
*/
//以上为自定义滤波
//以下为opencv掩膜api使用
double t = getTickCount();
Mat kernel = (Mat_<char>(3, 3) << 0, -1, 0, -1, 5, -1, 0, -1, 0);
filter2D(src, dst, src.depth(), kernel);
double timeconsume = (getTickCount() - t) / getTickFrequency();
printf("tim consume %.2f\n", timeconsume);
namedWindow("output img", CV_WINDOW_AUTOSIZE);
imshow("output img", dst);
waitKey(0);
return 0;
}
效果