碎片滤镜
Photoshop软件有一个碎片滤镜。我在实现碎片滤镜的过程中,发现只要改几个数就可以实现图像重影的效果。
将图像创建四个相互偏移的副本,叠加之后产生类似重影的效果。偏移方向为左上,左下,右上,右下,偏移角度为45度。将四个方向的偏移量累加求平均值作为中心点像素的值。各个方向的偏移量可以相同也可以不同。先来看相同的情况。
假如四个方向都偏移4个像素大小:
完整代码如下:
#include<opencv2/opencv.hpp>
#include <iostream>
using namespace cv;
using namespace std;
void chongYingFilter(Mat &srcImage);
int main(){
Mat srcImage = imread("lena.jpg");//图片在工程目录下,否则写绝对路径
if(!srcImage.data || srcImage.empty()){
cout<<"读入图片错误!"<<endl;
return -1;
}
imshow("原图",srcImage);
chongYingFilter(srcImage);
waitKey(0);
return 0;
}
void chongYingFilter(Mat &srcImage){
//偏移量两两配合,分别是左下,左上,右上,右下
int OffsetJ[4] = { 4, -4, -4, 4 };
int OffsetI[4] = { -4, -4, 4, 4 };
int sumB,sumG,sumR;
for(int j = 0;j<srcImage.rows;j++){
for(int i = 0;i<srcImage.cols;i++){
sumB = 0;sumG = 0;sumR = 0;
for(int k = 0;k<4;k++){
int JJ = j + OffsetJ[k];
int II = i + OffsetI[k];
//防止越界
if(JJ < 0){
JJ = 0;
}else if(JJ >= srcImage.rows){
JJ = srcImage.rows - 1;
}
if(II < 0){
II = 0;
}else if(II >= srcImage.cols){
II = srcImage.cols - 1;
}
//累加,求当前像素点的左下,左上,右上,右下四个偏移量的和
sumB += srcImage.at<Vec3b>(JJ,II)[0];
sumG += srcImage.at<Vec3b>(JJ,II)[1];
sumR += srcImage.at<Vec3b>(JJ,II)[2];
}
//求平均值,求平均值(sum+2)/4,
//为什么要+2,就为了四舍五入。比如如果计算结果为108.6,则取像素109更为合理
srcImage.at<Vec3b>(j,i)[2] = (sumR+2)>>2;
srcImage.at<Vec3b>(j,i)[1] = (sumG+2)>>2;
srcImage.at<Vec3b>(j,i)[0] = (sumB+2)>>2;
}
}
imshow("重影滤镜",srcImage);
}
效果如下图:
如果把偏移量调大呢?比如每个方向都是16个像素大小
int OffsetJ[4] = { 16, -16, -16, 16 };
int OffsetI[4] = { -16, -16, 16, 16 };
效果图如下:
如果只把一个方向的偏移量调大,其余三个一样大呢:
int OffsetJ[4] = { 6, -6, -6, 6 };
int OffsetI[4] = { -66, -6, 6, 6 };
这事产生重影,效果图如下:
如果想重影是上下方向呢?就像下图那样:
那就这样调偏移量:
int OffsetJ[4] = { 6, -6, -6, 66 };
int OffsetI[4] = { -6, -6, 6, 6 };
总结:还有其他变化吗?
当然,比如右下方向的偏移量比其他三个都要大,又会产生新的重影图像,亦或者把偏移数目调成8个,再增加上下左右四个偏移量,产生的图像又会是什么样呢???有兴趣的读者可以尝试一下,我这里就不一一列举了。
暗调滤镜
原理如下:
- R = R * R / 255
- G = G * G / 255
B = B * b / 255
完整代码如下:
#include<opencv2/opencv.hpp>
#include <iostream>
using namespace cv;
using namespace std;
void anDiaoFilter(Mat &srcImage);
int main(){
Mat srcImage = imread("lena.jpg");//图片在工程目录下,否则写绝对路径
if(!srcImage.data || srcImage.empty()){
cout<<"读入图片错误!"<<endl;
return -1;
}
imshow("原图",srcImage);
anDiaoFilter(srcImage);
waitKey(0);
return 0;
}
void anDiaoFilter(Mat &srcImage){
int rowNum = srcImage.rows;
int colNum = srcImage.cols * srcImage.channels();
for(int j = 0;j<rowNum;j++){
uchar* row = srcImage.ptr<uchar>(j);
for(int i = 0;i<colNum;i++){
row[i] = row[i] * row[i] >>8;
}
}
imshow("暗调滤镜",srcImage);
}
效果图如下: