颜色空间缩减(关键是缩减思想)
#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <iostream>
using namespace std;
using namespace cv;
void colorReduce(Mat& inputImage, Mat& outputImage, int div);//div就是分割区间大小,此例为10表示把0~256变成0~25
int main( ){
Mat srcImage = imread("1.jpg"); //【1】创建原始图
imshow("原始图像",srcImage); //并显示
Mat dstImage; //【2】按原始图的参数规格来创建创建效果图
dstImage.create(srcImage.rows,srcImage.cols,srcImage.type()); //效果图的大小、类型与原图片相同
double time0 = static_cast<double>(getTickCount()); //【3】记录起始时间
colorReduce(srcImage,dstImage,10); //【4】调用颜色空间缩减函数
time0 = ((double)getTickCount() - time0)/getTickFrequency(); //【5】计算运行时间并输出
cout<<"\t此方法运行时间为: "<<time0<<"秒"<<endl; //输出运行时间
imshow("效果图",dstImage); //【6】显示效果图
waitKey(0); //等待鼠标点击
}
void colorReduce(Mat& inputImage, Mat& outputImage, int div){//C操作符[ ]方法版的颜色空间缩减函数
outputImage = inputImage.clone(); //拷贝实参到临时变量
int rowNumber = outputImage.rows; //行数
int colNumber = outputImage.cols*outputImage.channels(); //列数 x 通道数=每一行元素的个数
for(int i = 0;i < rowNumber;i++){ //行循环处理
uchar* data = outputImage.ptr<uchar>(i); //获取第i行的首地址
for(int j = 0;j < colNumber;j++){ //列循环处理
data[j] = data[j]/div*div + div/2; //处理每个像素
}
}
}
动态地址运算配合at(关键是学会这种写法)
void colorReduce(Mat& inputImage, Mat& outputImage, int div){
outputImage = inputImage.clone(); //拷贝实参到临时变量
for(int i = 0;i < outputImage.rows;i++){ //行遍历
for(int j = 0;j < outputImage.cols;j++){//列遍历
outputImage.at<Vec3b>(i,j)[0] = outputImage.at<Vec3b>(i,j)[0]/div*div + div/2; //蓝色通道
outputImage.at<Vec3b>(i,j)[1] = outputImage.at<Vec3b>(i,j)[1]/div*div + div/2; //绿色通道
outputImage.at<Vec3b>(i,j)[2] = outputImage.at<Vec3b>(i,j)[2]/div*div + div/2; //红是通道
}
}
}
线性叠加
#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <iostream>
using namespace cv;
using namespace std;
bool ROI_AddImage();
bool LinearBlending();
bool ROI_LinearBlending();
void ShowHelpText();
int main( ){
if(ROI_AddImage( )){
cout<<endl<<"\n运行成功,得出了需要的图像";
}
waitKey(0);
return 0;
}
bool ROI_AddImage(){
Mat srcImage1= imread("dota_pa.jpg");// 【1】读入图像
Mat logoImage= imread("dota_logo.jpg");// 【1】读入图像
if( !srcImage1.data ) { printf("读取srcImage1错误~! \n"); return false; }
if( !logoImage.data ) { printf("读取logoImage错误~! \n"); return false; }
Mat imageROI= srcImage1(Rect(200,250,logoImage.cols,logoImage.rows));// 【2】定义一个Mat类型并给其设定ROI区域
Mat mask= imread("dota_logo.jpg",0);// 【3】加载掩模(必须是灰度图,所以第二个参数是0)
logoImage.copyTo(imageROI,mask);//【4】将掩膜拷贝到ROI
namedWindow("<1>利用ROI实现图像叠加示例窗口");// 【5】显示结果
imshow("<1>利用ROI实现图像叠加示例窗口",srcImage1);
return true;
}
bool LinearBlending(){
double alphaValue = 0.5;//【0】定义一些局部变量
double betaValue;//【0】定义一些局部变量
Mat srcImage2, srcImage3, dstImage;
srcImage2 = imread("mogu.jpg");// 【1】读取图像 ( 两幅图片需为同样的类型和尺寸 )
srcImage3 = imread("rain.jpg");// 【1】读取图像 ( 两幅图片需为同样的类型和尺寸 )
if( !srcImage2.data ) { printf("读取srcImage2错误! \n"); return false; }
if( !srcImage3.data ) { printf("读取srcImage3错误! \n"); return false; }
betaValue = ( 1.0 - alphaValue );// 【2】进行图像混合加权操作
addWeighted( srcImage2, alphaValue, srcImage3, betaValue, 0.0, dstImage);//0.0是偏移值
imshow( "<2>线性混合示例窗口【原图】", srcImage2 );// 【3】显示原图窗口
imshow( "<3>线性混合示例窗口【效果图】", dstImage );// 【3】显示原图窗口
return true;
}
bool ROI_LinearBlending(){
Mat srcImage4= imread("dota_pa.jpg",1);//【1】读取图像
Mat logoImage= imread("dota_logo.jpg");//【1】读取图像
if( !srcImage4.data ) { printf("读取srcImage4错误~! \n"); return false; }
if( !logoImage.data ) { printf("读取logoImage错误~! \n"); return false; }
Mat imageROI;//【2】定义一个Mat类型并给其设定ROI区域
imageROI= srcImage4(Rect(200,250,logoImage.cols,logoImage.rows));//方法一
//imageROI= srcImage4(Range(250,250+logoImage.rows),Range(200,200+logoImage.cols));//方法二
addWeighted(imageROI,0.5,logoImage,0.3,0.,imageROI);//【3】将logo线性叠加到原图上
imshow("<4>区域线性图像混合示例窗口",srcImage4);//【4】显示结果
return true;
}
imread的参数flag设值如下
flag=-1,8位深度,原通道
flag=0,8位深度,1通道
flag=1, 8位深度,3通道
flag=2,原深度,1通道
flag=3, 原深度,3通道
flag=4,8位深度 ,3通道
通道分离
#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <iostream>
using namespace cv;
using namespace std;
bool MultiChannelBlending();
void ShowHelpText();
int main( ){
if(MultiChannelBlending( ))
cout<<endl<<"\n运行成功,得出了需要的图像~! ";
waitKey(0);
return 0;
}
bool MultiChannelBlending(){
Mat srcImage;
Mat logoImage;
vector<Mat> channels;//通道向量,这个VECTOR有分别存三个通道的矩阵
Mat imageBlueChannel;
// 描述:多通道混合-蓝色分量部分,BGR,所以蓝是0通道
logoImage= imread("dota_logo.jpg",0);// 【1】读入图片并转灰度
srcImage= imread("dota_jugg.jpg");// 【1】读入图片
if( !logoImage.data ) { printf("Oh,no,读取logoImage错误~! \n"); return false; }
if( !srcImage.data ) { printf("Oh,no,读取srcImage错误~! \n"); return false; }
split(srcImage,channels);//【2】把一个3通道图像转换成3个单通道图像:分离色彩通道
imageBlueChannel= channels.at(0);//【3】将原图蓝色通道引用返回给imageBlueChannel,注意引用,相当于两者等价,修改其中一个另一个跟着变
//【4】将原图的蓝色通道的(500,250)坐标处右下方的一块区域和logo图进行加权操作,将得到的混合结果存到imageBlueChannel中//省略了设置ROI语句
addWeighted(imageBlueChannel(Rect(500,250,logoImage.cols,logoImage.rows)),1.0,
logoImage,0.5,0,imageBlueChannel(Rect(500,250,logoImage.cols,logoImage.rows)));
merge(channels,srcImage);//【5】将三个单通道重新合并成一个三通道
namedWindow(" <1>游戏原画+logo蓝色通道");
imshow(" <1>游戏原画+logo蓝色通道",srcImage);//【6】显示效果图
return true;
}
亮度与对比度
#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include "opencv2/imgproc/imgproc.hpp"
#include <iostream>
using namespace std;
using namespace cv;
static void ContrastAndBright(int, void *);
int g_nContrastValue; //对比度值
int g_nBrightValue; //亮度值
Mat g_srcImage,g_dstImage;
int main( ){
g_srcImage = imread( "1.jpg");
if( !g_srcImage.data ) { printf("读取g_srcImage图片错误~! \n"); return false; }
g_dstImage = Mat::zeros( g_srcImage.size(), g_srcImage.type() );//创建矩阵值为0,尺寸同src,图片种类同src
g_nContrastValue=80;//设定对比度和亮度的初值
g_nBrightValue=80;//设定对比度和亮度的初值
namedWindow("【效果图窗口】", 1);//创建窗口
createTrackbar("对比度:", "【效果图窗口】",&g_nContrastValue, 300,ContrastAndBright );//创建轨迹条
createTrackbar("亮 度:", "【效果图窗口】",&g_nBrightValue, 200,ContrastAndBright );//创建轨迹条
ContrastAndBright(g_nContrastValue,0);//调用回调函数
ContrastAndBright(g_nBrightValue,0);//调用回调函数
cout<<endl<<"\t运行成功,请调整滚动条观察图像效果\n\n"<<"\t按下“q”键时,程序退出\n";//输出一些帮助信息
while(char(waitKey(1)) != 'q') {}//按下“q”键时,程序退出
return 0;
}
static void ContrastAndBright(int, void *){
namedWindow("【原始图窗口】", 1);// 创建窗口
for( int y = 0; y < g_srcImage.rows; y++ )//行遍历
for( int x = 0; x < g_srcImage.cols; x++ )//列遍历
for( int c = 0; c < 3; c++ )// 通道遍历,执行运算 g_dstImage(i,j) = a*g_srcImage(i,j) + b 对比度是乘通道值,亮度是偏移
g_dstImage.at<Vec3b>(y,x)[c] = saturate_cast<uchar>( (g_nContrastValue*0.01)*( g_srcImage.at<Vec3b>(y,x)[c] ) + g_nBrightValue );
imshow("【原始图窗口】", g_srcImage);// 显示图像
imshow("【效果图窗口】", g_dstImage);// 显示图像
}
PS:000是黑,255255255是白
DFT
#include "opencv2/core/core.hpp"
#include "opencv2/imgproc/imgproc.hpp"
#include "opencv2/highgui/highgui.hpp"
#include <iostream>
using namespace cv;
int main( ){
//【1】以灰度模式读取原始图像并显示
Mat srcImage = imread("1.jpg", 0);
if(!srcImage.data ) { printf("读取图片错误,请确定目录下是否有imread函数指定图片存在~! \n"); return false; }
imshow("原始图像" , srcImage);
//【2】将输入图像延扩到最佳的尺寸,边界用0补充
int m = getOptimalDFTSize( srcImage.rows );
int n = getOptimalDFTSize( srcImage.cols );
//将添加的像素初始化为0.
Mat padded;
copyMakeBorder(srcImage, padded, 0, m - srcImage.rows, 0, n - srcImage.cols, BORDER_CONSTANT, Scalar::all(0));
//【3】为傅立叶变换的结果(实部和虚部)分配存储空间。
//将planes数组组合合并成一个多通道的数组complexI
Mat planes[] = {Mat_<float>(padded), Mat::zeros(padded.size(), CV_32F)};
Mat complexI;
merge(planes, 2, complexI);
//【4】进行就地离散傅里叶变换
dft(complexI, complexI);
//【5】将复数转换为幅值,即=> log(1 + sqrt(Re(DFT(I))^2 + Im(DFT(I))^2))
split(complexI, planes); // 将多通道数组complexI分离成几个单通道数组,planes[0] = Re(DFT(I), planes[1] = Im(DFT(I))
magnitude(planes[0], planes[1], planes[0]);// planes[0] = magnitude
Mat magnitudeImage = planes[0];
//【6】进行对数尺度(logarithmic scale)缩放
magnitudeImage += Scalar::all(1);
log(magnitudeImage, magnitudeImage);//求自然对数
//【7】剪切和重分布幅度图象限
//若有奇数行或奇数列,进行频谱裁剪
magnitudeImage = magnitudeImage(Rect(0, 0, magnitudeImage.cols & -2, magnitudeImage.rows & -2));
//重新排列傅立叶图像中的象限,使得原点位于图像中心
int cx = magnitudeImage.cols/2;
int cy = magnitudeImage.rows/2;
Mat q0(magnitudeImage, Rect(0, 0, cx, cy)); // ROI区域的左上
Mat q1(magnitudeImage, Rect(cx, 0, cx, cy)); // ROI区域的右上
Mat q2(magnitudeImage, Rect(0, cy, cx, cy)); // ROI区域的左下
Mat q3(magnitudeImage, Rect(cx, cy, cx, cy)); // ROI区域的右下
//交换象限(左上与右下进行交换)
Mat tmp;
q0.copyTo(tmp);
q3.copyTo(q0);
tmp.copyTo(q3);
//交换象限(右上与左下进行交换)
q1.copyTo(tmp);
q2.copyTo(q1);
tmp.copyTo(q2);
//【8】归一化,用0到1之间的浮点值将矩阵变换为可视的图像格式
normalize(magnitudeImage, magnitudeImage, 0, 1, NORM_MINMAX);
//【9】显示效果图
imshow("频谱幅值", magnitudeImage);
waitKey();
return 0;
}
低通滤波会让图像变得模糊,可以对图像进行模糊处理,滤除图像的噪声,高通滤波获得了图像的边缘和纹理信息。此外,通过增强图像的高频信号,可以增强图像的对比度,因为图像中的高频信号主要是出现在边缘及噪声这样的灰度出现跃变处的区域。