公式及原理
公式:
原理上大概是对每个像素点运用公式将其与其周围的四个像素点进行修改操作
代码
#include<iostream>
#include<vector>
#include<opencv2/opencv.hpp>
using namespace std;
using namespace cv;
int main() {
Mat Img = imread("1.jpg");//选定一张目标图片
namedWindow("nochange", CV_WINDOW_NORMAL);
imshow("nochange", Img);//显示原图
int rows = Img.rows;//需要遍历的行
int cols = (Img.cols - 1)*Img.channels();//需要遍历的列
int offsetx = Img.channels();//基本操作单位
Mat Img2 = Mat::zeros(Img.size(), Img.type());//一个与Img类型大小相同的全0矩阵
for (int i = 1; i < rows - 1; i++) {
//定义行指针
uchar* previous = Img.ptr<uchar>(i - 1);
uchar* current = Img.ptr<uchar>(i);
uchar* next = Img.ptr<uchar>(i + 1);
uchar* output = Img2.ptr<uchar>(i);//传地址 所以下面对output进行的修改直接改在Img2上
for (int j = offsetx; j < cols; j++) {
//saturate_cast<uchar>();函数的调用
output[j] = saturate_cast<uchar>(current[j] * 5 - (current[j - offsetx] + current[j + offsetx] + previous[j] + next[j]));
}
}
namedWindow("change", CV_WINDOW_NORMAL);
imshow("change", Img2);//显示修改后的图片
waitkey();
}
需要遍历的列数和图片本身的列数可能是不一样的,这涉及到图片通道数的问题。比如说,如果图片是单通道,那么需要遍历的列数=图片本身的列数,因为单通道图片每个像素点只有一个值来表示;但是如果图片是三通道的RGB图片,那么需要遍历的列数=3*图片本身的列数,因为三通道图片的每个像素点都有三个值来表示。
在用公式的时候要用到offsetx数值,这里即图片的通道数。因为每次进行的实际上是每个像素点与周围四个像素点的对应数值上的操作。单通道图片倒没什么影响,因为它每个像素点只有一个数值表示;而三通道图片有三个数值,第一个数值就应该跟周围四个像素点的第一个数值进行操作,以此类推。
自动处理像素范围函数saturate_cast<typename _Tp>()
用于确保经修改后每个像素点RGB数值在0~255之间
用filter2D方法实现
部分代码
Mat kernel = (Mat_<char>(3, 3) << 0, -1, 0, -1, 5, -1, 0, -1, 0);//定义一个掩膜 这个是上面的代码对应的掩膜
filter2D(Img, Img2, Img.depth(), kernel);
namedWindow("change", CV_WINDOW_NORMAL);
imshow("change", Img2);
实现效果跟上面的代码一样。只是你定义了什么样的掩膜,他就会执行什么样的操作,然后出对应的效果。
Img和Img2是Mat类型变量,是把Img修改后的内容赋给Img2(此时Img本身没有被改变)。
depth是图片的深度属性,有32、24、8。如果不知道的话就用-1或者原图.depth(),表示深度和原图一致。