Q6:减色处理
减色处理就是将图片的256^3个色调变成4^3个色调,也就是将原来每个通道256个颜色级分成四个区间压缩到4个颜色级,这四个灰度级是给出的,分别是32,96,160,224。以(32,96,160,224)为例,在程序中要满足下面的关系。
pix=32 (0<pix<64)
96 (64<pix<128)
160 (128<pix<192)
224 (192<pix<256)
由上面的关系得到关系式
pix=(int)(pix/64)*64+32
代码如下。
#include"iostream"
#include"opencv2/core/core.hpp"
#include"opencv2/highgui/highgui.hpp"
#include<opencv2/opencv.hpp>
#include<math.h>
using namespace cv;
using namespace std;
Mat decline_color(Mat img){
int imgrow = img.rows;
int imgcol = img.cols;
int channel=img.channels();
Mat de_color = Mat::zeros(imgrow,imgcol,CV_8UC3);
for(int j=0;j<imgrow;j++){
for(int i=0;i<imgcol;i++){
for(int k=0;k<channel;k++){
de_color.at<Vec3b>(j,i)[k] = (uchar)(floor((double)(img.at<Vec3b>(j,i)[k])/64)*64+32);
}
}
}
return de_color;
}
void main(){
Mat img = imread("ck567.jpg",IMREAD_COLOR);
Mat out = decline_color(img);
imshow("sample",out);
waitKey(0);
destroyAllWindows();
}
这里采用的floor()函数是向下取整函数,求得像素值除以64的整数部分,对应前面分析的关系式。
效果如下
Q7:平均池化
平均池化就是将图片分割为若干个区域,分别算出来每个区域的像素平均值,并把该区域所有的像素值全部改为平均值。这种网格划分并求出平均值的操作定义为平均池化。
代码如下
#include"iostream"
#include"opencv2/core/core.hpp"
#include"opencv2/highgui/highgui.hpp"
#include<opencv2/opencv.hpp>
#include<math.h>
using namespace cv;
using namespace std;
Mat average_pooling(Mat img){
int imgrow = img.rows;
int imgcol = img.cols;
int channel = img.channels();
Mat out = Mat::zeros(imgrow,imgcol,CV_8UC3);
int step = 5;
double grid_sum;
for(int j=0;j<imgrow;j+=step){ //行
for(int i=0;i<imgcol;i+=step){ //列
for(int k=0;k<channel;k++){ //通道
grid_sum=0;
for(int j_=0;j_<step;j_++){
for(int i_=0;i_<step;i_++){
grid_sum += (double)img.at<Vec3b>(j+j_,i+i_)[k];
}
}
grid_sum /= (step*step);
for(int j_=0;j_<step;j_++){
for(int i_=0;i_<step;i_++){
out.at<Vec3b>(j+j_,i+i_)[k] = (uchar)grid_sum;
}
}
}
}
}
return out;
}
void main(){
Mat img = imread("ck567.jpg",IMREAD_COLOR);
cout<<"行数:"<<img.rows<<" "<<"列数:"<<img.cols<<endl;
Mat out = average_pooling(img);
imshow("sample",out);
waitKey(0);
destroyAllWindows();
}
这里要注意的一个问题就是程序中step的赋值,step表示分割的网格的尺寸,大小为step*step,如果随意赋一个值,很容易出现下面的错误。错误的大意是参数越界。
因此step的值很重要,关系到程序是否能正常运行,网格的尺寸需要根据图像做出调整可以使用下面的语句获取图像的尺寸,z知道尺寸之后就可以确定step,这里用的图片是325*580,所以网格尺寸定为5*5,也就是分成(325/5)*(580/5)个网格。
cout << "行数:" << img.rows << " " << "列数:" << img.cols << endl;
上述程序的效果如下所示,可以看到平均池化后的图像画质很模糊,分割的网格尺寸越小,图像越清晰,这个技术很常见的应用就是图像或视频中的马赛克处理。
Q8:最大池化
最大池化就是取网格中的最大值进行赋值,而不再是平均值。代码如下。该段代码与平均池化的代码相差不多,只要将平均池化中取平均值的部分修改为取最大值就可以了。
#include"iostream"
#include"opencv2/core/core.hpp"
#include"opencv2/highgui/highgui.hpp"
#include<opencv2/opencv.hpp>
#include<math.h>
using namespace cv;
using namespace std;
Mat max_pooling(Mat img){
int imgrow = img.rows;
int imgcol = img.cols;
int channel = img.channels();
Mat out = Mat::zeros(imgrow,imgcol,CV_8UC3);
int step = 5;
double pixmax;
for(int j=0;j<imgrow;j+=step){ //行
for(int i=0;i<imgcol;i+=step){ //列
for(int k=0;k<channel;k++){ //通道
pixmax=0;
for(int j_=0;j_<step;j_++){
for(int i_=0;i_<step;i_++){
if((double)img.at<Vec3b>(j+j_,i+i_)[k]>pixmax){
pixmax = (double)img.at<Vec3b>(j+j_,i+i_)[k];
}
}
}
for(int j_=0;j_<step;j_++){
for(int i_=0;i_<step;i_++){
out.at<Vec3b>(j+j_,i+i_)[k] = (uchar)pixmax;
}
}
}
}
}
return out;
}
void main(){
Mat img = imread("ck567.jpg",IMREAD_COLOR);
cout<<"行数:"<<img.rows<<" "<<"列数:"<<img.cols<<endl;
Mat out = max_pooling(img);
imshow("sample",out);
waitKey(0);
destroyAllWindows();
}
效果如下。与平均池化的效果相比,最大池化的局部色彩更加鲜明,但整体上呈现的效果还是平均池化更好一些。