*********************2016.8.22***********************
@2016.8.9~2016.8.12 OpenCV学习细节总结
1.直接读取图像灰度图的方法:Mat LogoMask = imread(“Logo.jpg”, 0);
2.掩模必须为灰度图
3.获取图像ROI的方法:Mat GirlROI = Girl(Rect(200, 200, Logo.cols, Logo.rows));
4.分离颜色通道时候 须要定义 vector channels ——–> 须要搞懂!先保留问题
5.OpenCV的色彩空间为 BGR
6.亮度对比度调节理论依据:g(i,j)=a*f(i,j)+b(其中a为对比度,b为亮度)
7.OpenCV 源代码中的定义:
typedef Vec
Vec2b—表示每个Vec2b对象中,可以存储2个char(字符型)数据
Vec3b—表示每一个Vec3b对象中,可以存储3个char(字符型)数据,比如可以用这样的对象,去存储RGB图像中的
Vec4b—表示每一个Vec4b对象中,可以存储4个字符型数据,可以用这样的类对象去存储—4通道RGB+Alpha的图
8.二维图像的遍历像素方法如下(详情查看Mat::at)
Mat H(100, 100, CV_64F);
for (int i = 0; i < H.rows; i++)
{
for (int j = 0; j < H.cols; j++)
{
H.at<double>(i, j) = 1. / (i + j + 1);
}
}
9.三通道图像的遍历像素方法如下
for (int y = 0; y < SrcImg.rows; ++y)
{
for (int x = 0; x < SrcImg.cols; ++x)
{
for (int c = 0; c < 3; ++c)
{
DstImg.at(y, x)[c]= saturate_cast((ContrastValue*0.01)*SrcImg.at(y,x)[c]+BrightValue);
}
}
}
10.滤波函数内核的大小不能为0,否则会报错
11.滤波函数内核的大小最好都为奇数。
@2016.8.9~2016.8.12 OpenCV学习函数总结
1.两图像加权融合:addWeighted()
2.分离图像通道:vector channels;
split(Girl, channels);
3.读取BGR中的其中一通道(B为0,G为1,R为2):B=channels.at(0);G=channels.at(1);R=channels.at(2)
4.三通道合成:Merge(channels,OutputDst);
5.运算结果可能超出像素取值范围(溢出),还可能是非整数(如果是浮点数的话),用来确保有效值:saturate_cast<…>()
saturate in the name means that when the input value v is out of the range of the target type
the result is not formed just by taking low bits of the input, but instead the value is clipped.For example :
uchar a = saturate_cast(-100); // a = 0 (UCHAR_MIN)
short b = saturate_cast(33333.33333); // b = 32767 (SHRT_MAX)
6.用于初始化输出图像,使输出图像与输入图像有相同的尺寸类型:
boxFilterDstImg = Mat::zeros(SrcImg.size(), SrcImg.type());
或者
boxFilterDstImg = SrcImg.clone();
7.创建拉动条:createTrackbar()
8.三种线性滤波函数:boxFilter();blur();GaussianBlur();
9.二种非线性滤波函数:medianBlur();bilateralFilter();
10.Returns a structuring element of the specified size and shape for morphological operations(形态学变换用的核):getStructuringElement()
11.
形态学变换初级 dilate(),erode()
形态学变换高级 morphologyEx(MORPH_OPEN /MORPH_CLOSE/ MORPH_GRADIENT/ MORPH_TOPHAT/ MORPH_BLACKHAT)
12.三种边缘检测与一个服务于Sobel 的滤波器
Canny,Sobel,Laplacian/ Scharr滤波器
*********************2016.8.21***********************
@边缘检测的一般步骤
原图->滤波->转化为灰度图->Canny()/Sobel()【其中Scharr滤波器专为Sobel()函数设计】/Laplacian()。
@两个比较重要的函数
转化为灰度图用的函数:cvtColor()
其他类型格式转化为CV_8U用的函数:convertScaleAbs()
@两个等价的函数
Scharr(src, dst, ddepth, dx, dy, scale,delta, borderType);
<<=====>>Sobel(src, dst, ddepth, dx, dy, CV_SCHARR,scale, delta, borderType);
@Canny,Sobel,Laplacian,Scharr用法源代码
bool Canny()
{
Mat SrcImg = imread("benz.jpg");
if (!SrcImg.data)
return false;
Mat EdgeImg;
Mat BWImg;
Mat DstImg;
cvtColor(SrcImg, BWImg, CV_RGB2GRAY);
blur(BWImg, BWImg, Size(3, 3));
//第三个参数,double类型的threshold1,第一个滞后性阈值。
//第四个参数,double类型的threshold2,第二个滞后性阈值。
//这个函数阈值1和阈值2两者的小者用于边缘连接,而大者用来控制强边缘的初始段
//推荐的高低阈值比在2:1到3:1之间。
Canny(BWImg, EdgeImg, 3, 9);
//void copyTo(OutputArray m, InputArray mask) const;
//! copies those matrix elements to "m" that are marked with non-zero mask elements.
SrcImg.copyTo(DstImg, EdgeImg);
namedWindow("BWGirl");
imshow("BWGirl", DstImg);
}
bool Sobel()
{
Mat SrcImgRGB = imread("benz.jpg");
if (!SrcImgRGB.data)
return false;
Mat DstImgx, DstImgy, DstImg, absDstImgx, absDstImgy;
Mat SrcImgBW;
cvtColor(SrcImgRGB, SrcImgBW, CV_RGB2GRAY);
//Sobel与Scharr滤波器是等价的
//Scharr(..........) <==> Sobel(Src,Dst,CV_16S,1,0,Scharr)
//ksize – Size of the extended Sobel kernel. It must be 1, 3, 5, or 7.
//以下默认为Ksize=1
Sobel(SrcImgBW, DstImgx, CV_8U, 1, 0);
Sobel(SrcImgBW, DstImgy, CV_8U, 0, 1);
addWeighted(DstImgx, 0.5, DstImgy, 0.5, 0, DstImg);
namedWindow("Sobel x方向");
namedWindow("Sobel y方向");
namedWindow("Sobel x,y方向通过加权叠加");
namedWindow("原图");
imshow("Sobel x方向", DstImgx);
imshow("Sobel y方向", DstImgy);
imshow("Sobel x,y方向通过加权叠加", DstImg);
imshow("原图", SrcImgRGB);
}
//Scharr滤波器,不是算子。
bool Scharr()
{
Mat SrcImg, GraySrcImg;
Mat DstImgX, DstImgY;
Mat AbsDstImgX, AbsDstImgY;
Mat DstImg;
SrcImg = imread("benz.jpg");
if (!SrcImg.data)
return false;
//中值滤波
medianBlur(SrcImg, SrcImg, 3);
//转化为灰度图
cvtColor(SrcImg, GraySrcImg, CV_RGB2GRAY);
//计算x,y方向的导数
Scharr(GraySrcImg, DstImgX, CV_16S, 1, 0);
Scharr(GraySrcImg, DstImgY, CV_16S, 0, 1);
//转化为CV_8U
convertScaleAbs(DstImgX, AbsDstImgX);
convertScaleAbs(DstImgY, AbsDstImgY);
//加权融合
addWeighted(AbsDstImgX, 0.5, AbsDstImgY, 0.5, 0, DstImg);
namedWindow("滤波后的图");
imshow("滤波后的图", DstImg);
}
bool Laplacian()
{
Mat SrcImg, GraySrcImg, DstImg;
SrcImg = imread("benz.jpg");
//先对RGB图像滤波,滤波完后再转化为灰度图。
GaussianBlur(SrcImg, SrcImg, Size(3, 3), 0);
cvtColor(SrcImg, GraySrcImg, CV_RGB2GRAY);
//通过拉普拉斯变换边缘检测函数的核有默认值1,核越大,边缘越明显
//tips:也可以试试改变输出图像不同深度,再转化为8U,效果是不同的。
//第三个参数,int类型的ddepth,输出图像的深度,支持如下src.depth()和ddepth的组合:
//若src.depth() = CV_8U, 取ddepth = -1 / CV_16S / CV_32F / CV_64F
//若src.depth() = CV_16U / CV_16S, 取ddepth = -1 / CV_32F / CV_64F
//若src.depth() = CV_32F, 取ddepth = -1 / CV_32F / CV_64F
//若src.depth() = CV_64F, 取ddepth = -1 / CV_64F
Laplacian(GraySrcImg, DstImg, CV_16U, 3);
//进行CV_16U---->CV_8U的函数
//convertScaleAbs:On each element of the input array, the function convertScaleAbs performs three operations sequentially:
//scaling, taking an absolute value, conversion to an unsigned 8-bit type:
convertScaleAbs(DstImg, DstImg);
namedWindow("灰度图");
namedWindow("拉普拉斯变换图");
imshow("灰度图", GraySrcImg);
imshow("拉普拉斯变换图", DstImg);
}
@在学习浅墨的OpenCV入门教程(Soble算子)遇到的问题思考
在学习Sobel算子时,浅墨的代码如下:
int main( )
{
//【0】创建 grad_x 和 grad_y 矩阵
Mat grad_x, grad_y;
Mat abs_grad_x, abs_grad_y,dst;
//【1】载入原始图
Mat src = imread("1.jpg"); //工程目录下应该有一张名为1.jpg的素材图
//【2】显示原始图
imshow("【原始图】sobel边缘检测", src);
//【3】求 X方向梯度
Sobel( src, grad_x, CV_16S, 1, 0, 3, 1, 1, BORDER_DEFAULT );
convertScaleAbs( grad_x, abs_grad_x );
imshow("【效果图】 X方向Sobel", abs_grad_x);
//【4】求Y方向梯度
Sobel( src, grad_y, CV_16S, 0, 1, 3, 1, 1, BORDER_DEFAULT );
convertScaleAbs( grad_y, abs_grad_y );
imshow("【效果图】Y方向Sobel", abs_grad_y);
//【5】合并梯度(近似)
addWeighted( abs_grad_x, 0.5, abs_grad_y, 0.5, 0, dst );
imshow("【效果图】整体方向Sobel", dst);
waitKey(0);
return 0;
}
然后我问了自己一个问题:
//【3】求 X方向梯度
Sobel( src, grad_x, CV_16S, 1, 0, 3, 1, 1, BORDER_DEFAULT );
//【4】求Y方向梯度
Sobel( src, grad_y, CV_16S, 0, 1, 3, 1, 1, BORDER_DEFAULT );
为什么目标图像的深度要转化为CV_16S(16位有符号)类型呢?
接下去发现,浅墨的代码在后续又将其转化成为8位无符号,代码如下:
convertScaleAbs( grad_x, abs_grad_x );
convertScaleAbs( grad_y, abs_grad_y );
通过了查询帮助文档了解convertScaleAbs这个函数:
On each element of the input array, the function convertScaleAbs performs three operations sequentially: scaling, taking an absolute value, conversion to an unsigned 8-bit type。
那么我直接在Sobel函数中填入CV_8U的参数呢????!!!!
于是,有了下面这两张图片的对比:其中第一张为直接在Sobel函数里面填入CV_8U,第二张为Sobel输出CV_16S后通过convertScaleAbs()转化为CV_8U.仔细看还是有那么一点差别的(ps:原图为RGB,没有转化为灰度图像,不知道会不会这个因素有影响。。。)
通过cvtColor(Src,Dst,CV_RGB2GRAY)将原图转为灰度图后再看效果:
嗯,还是有差别的!!!!
@膨胀/腐蚀,开运算/闭运算,顶帽/黑帽综合代码
#include
#include
#include
using namespace std;
using namespace cv;
//全局变量
Mat SrcImg;
Mat DstImg;
/*源代码:enum { MORPH_RECT=0, MORPH_CROSS=1, MORPH_ELLIPSE=2 };*/
int ElementShape = MORPH_RECT;
//10为分界点,超过10与小于10各对应两种状态
int DilateErodeValue = 11;
int OpenCloseValue = 11;
int TopBlackHatValue = 11;
//回调函数声明
void CallbackDilateErode(int, void*);
void CallbackOpenClose(int, void*);
void CallbackTopBlackHat(int, void*);
//打印在DOS界面的帮助信息
void PrintHelpText();
//主函数
int main()
{
SrcImg = imread("Logo.jpg");
if (!SrcImg.data)
return false;
PrintHelpText();
DstImg = SrcImg.clone();
//命名窗口一定要先创建
//之前在回调函数里面才创建命名窗口,导致Trackbar显示不出来
namedWindow("膨胀腐蚀效果图");
namedWindow("开闭运算效果图");
namedWindow("顶黑帽运算效果图");
createTrackbar("腐蚀与膨胀", "膨胀腐蚀效果图", &DilateErodeValue, 20, CallbackDilateErode);
createTrackbar("开闭运算", "开闭运算效果图", &OpenCloseValue, 20, CallbackOpenClose);
createTrackbar("顶黑帽运算", "顶黑帽运算效果图", &TopBlackHatValue, 20, CallbackTopBlackHat);
namedWindow("原图");
imshow("原图", SrcImg);
//轮询获取按键信息
while (1)
{
int getKeyInput = waitKey(0);//获取按键的ASCII码
//Trackbar改变的时候调用回调函数
CallbackDilateErode(DilateErodeValue, 0);
CallbackOpenClose(OpenCloseValue, 0);
CallbackTopBlackHat(TopBlackHatValue, 0);
//根据按键的输入,改变核的形状
if (27 == (char)getKeyInput)//ESC
{
break;
}
else if ('A'==(char)getKeyInput)
{
ElementShape = MORPH_RECT;
}
else if ('S' == (char)getKeyInput)
{
ElementShape = MORPH_ELLIPSE;
}
else if ('D' == (char)getKeyInput)
{
ElementShape = MORPH_CROSS;
}
else if(' '== (char)getKeyInput)//空格
{
ElementShape = (ElementShape + 1) % 3;//三种状态顺序切换
}
}
waitKey();
return true;
}
/*回调函数中的Offset表示偏移的中心点*/
void CallbackDilateErode(int ,void*)
{
int Offset = 10;
int AbsOffset = (DilateErodeValue - Offset) > 0 ? (DilateErodeValue - Offset) : -(DilateErodeValue - Offset);
Mat element=getStructuringElement(ElementShape, Size(AbsOffset * 2 + 1, AbsOffset * 2 + 1));
if (DilateErodeValue > 10)//腐蚀
{
morphologyEx(SrcImg, DstImg, MORPH_ERODE, element);
}
else//膨胀
{
morphologyEx(SrcImg, DstImg, MORPH_DILATE, element);
}
imshow("膨胀腐蚀效果图", DstImg);
}
void CallbackOpenClose(int, void*)
{
int Offset = 10;
int AbsOffset = (OpenCloseValue - Offset) > 0 ? (OpenCloseValue - Offset) : -(OpenCloseValue - Offset);
Mat element = getStructuringElement(ElementShape, Size(AbsOffset * 2 + 1, AbsOffset * 2 + 1));
if (OpenCloseValue > 10)//闭运算
{
morphologyEx(SrcImg, DstImg, MORPH_CLOSE, element);
}
else//开运算
{
morphologyEx(SrcImg, DstImg, MORPH_OPEN, element);
}
imshow("开闭运算效果图", DstImg);
}
void CallbackTopBlackHat(int, void*)
{
int Offset = 10;
int AbsOffset = (TopBlackHatValue - Offset) > 0 ? (TopBlackHatValue - Offset) : -(TopBlackHatValue - Offset);
Mat element = getStructuringElement(ElementShape, Size(AbsOffset * 2 + 1, AbsOffset * 2 + 1));
if (TopBlackHatValue > 10)//黑帽运算
{
morphologyEx(SrcImg, DstImg, MORPH_BLACKHAT, element);
}
else//闭帽运算
{
morphologyEx(SrcImg, DstImg, MORPH_TOPHAT, element);
}
imshow("顶黑帽运算效果图", DstImg);
}
//DOS界面下显示帮助信息
void PrintHelpText()
{
printf( "\t\t\t\t\ 帮助信息"
"\n\t 按下按键ESC退出"
"\n\t 按下A------->掩膜形状为MORPH_RECT"
"\n\t 按下S------->掩膜形状为MORPH_ELLOPSE"
"\n\t 按下D------->掩膜形状为MORPH_CROSS"
"\n\t 按下SPACE------->掩膜形状为三种顺序切换");
}
*********************2016.8.20***********************
@数学形态学
数学形态学(Mathematical morphology) 是一门建立在格论和拓扑学基础之上的图像分析学科,是数学形态学图像处理的基本理论。其基本的运算包括:二值腐蚀和膨胀、二值开闭运算、骨架抽取、极限腐蚀、击中击不中变换、形态学梯度、Top-hat变换、颗粒分析、流域变换、灰值腐蚀和膨胀、灰值开闭运算、灰值形态学梯度等。
开运算:Dst=Open(Src,element)=dilate(erode(Src,element));
闭运算:Dst=Close(Src,element)=erode(dilate(Src,element));
简单来讲,形态学操作就是基于形状的一系列图像处理操作。OpenCV为进行图像的形态学变换提供了快捷、方便的函数。最基本的形态学操作有二种,他们是:膨胀与腐蚀(Dilation与Erosion)。
在进行腐蚀和膨胀的讲解之前,首先需要注意,腐蚀和膨胀是对白色部分(高亮部分)而言的,不是黑色部分。膨胀就是图像中的高亮部分进行膨胀,“领域扩张”,效果图拥有比原图更大的高亮区域。腐蚀就是原图中的高亮部分被腐蚀,“领域被蚕食”,效果图拥有比原图更小的高亮区域。
@openCV练习中图像读取不出来的问题
有时候图像读取失败可以试卷改 DEBUG 或者 RELEASE 模式
*********************2016.8.19***********************
@感觉双边滤波更接近于磨皮的效果。
@中值滤波与均值滤波器比较
中值滤波器与均值滤波器比较的优势:在均值滤波器中,由于噪声成分被放入平均计算中,所以输出受到了噪声的影响,但是在中值滤波器中,由于噪声成分很难选上,所以几乎不会影响到输出。因此同样用3x3区域进行处理,中值滤波消除的噪声能力更胜一筹。中值滤波无论是在消除噪声还是保存边缘方面都是一个不错的方法。
中值滤波器与均值滤波器比较的劣势:中值滤波花费的时间是均值滤波的5倍以上。
中值滤波在一定条件下,可以克服线性滤波器(如均值滤波等)所带来的图像细节模糊,如下图:
@方框滤波&均值滤波&高斯滤波&中值滤波&双边滤波 源代码
#include
#include
#include
#include
using namespace cv;
using namespace std;
//main函数与回调函数都要使用到-->所以定义成全局变量
Mat SrcImg;//输入图像
Mat boxFilterDstImg;//方框滤波输出图像
Mat blurDstImg;//均值滤波输出图像
Mat GaussianBlurDstImg;//高斯滤波输出图像
Mat meddianBlurDstImg;//中值滤波输出图像
Mat bilateralBlurDstImg;//双边滤波输出图像
//设定滤波函数的内核大小的初值
int boxFilterValue = 2;
int blurValue = 2;
int GaussianBlurValue = 2;
int meddianBlurValue = 7;
int bilateralBulrValue = 25;
//回调函数的声明
void CallbackBoxFilter(int, void*);
void CallbackBlur(int, void*);
void CallbackGaussianBlur(int, void*);
void CallbackMeddianBlur(int, void*);
void CallbackBilateralBlur(int, void*);
//主函数
int main()
{
//DOS界面颜色
system("color 1C");
SrcImg = imread("Dragon.jpg");
if (!SrcImg.data)
{
printf("读取图片失败");
return false;
}
//用于初始化输出图像,使输出图像与输入图像有相同的尺寸类型
//但是好像不用初始化也可以
//boxFilterDstImg = Mat::zeros(SrcImg.size(), SrcImg.type());
//blurDstImg= Mat::zeros(SrcImg.size(), SrcImg.type());
//GaussianBlurDstImg = Mat::zeros(SrcImg.size(), SrcImg.type());
//也可以用clone函数来实现输出图像与输入图像有相同的尺寸类型
boxFilterDstImg = SrcImg.clone();
blurDstImg= SrcImg.clone();
GaussianBlurDstImg= SrcImg.clone();
meddianBlurDstImg= SrcImg.clone();
bilateralBlurDstImg= SrcImg.clone();
//创建调用回调函数的Trackbar函数
createTrackbar("方框滤波", "方框滤波效果图", &boxFilterValue, 20, CallbackBoxFilter);
createTrackbar("均值滤波", "均值滤波效果图", &blurValue, 20, CallbackBlur);
createTrackbar("高斯滤波", "高斯滤波效果图", &GaussianBlurValue, 20, CallbackGaussianBlur);
createTrackbar("中值滤波", "中值滤波效果图", &meddianBlurValue, 35, CallbackMeddianBlur);
createTrackbar("双边滤波", "双边滤波效果图", &bilateralBulrValue, 100, CallbackBilateralBlur);
//Trackbar发生变化时调用的回调函数
CallbackBoxFilter(boxFilterValue, 0);
CallbackBlur(blurValue, 0);
CallbackGaussianBlur(GaussianBlurValue, 0);
CallbackMeddianBlur(meddianBlurValue, 0);
CallbackBilateralBlur(bilateralBulrValue, 0);
//显示原图
namedWindow("原图");
imshow("原图", SrcImg);
//输出一些帮助信息
cout <"\t\t\tby我不是斗哥";
waitKey();
return true;
}
//========================================================================
//滤波函数内核的大小不能为0,否则会报错
//所以Size(m,n)里面的数值都+1;
//高斯函数的内核m,n只能为奇数
//========================================================================
//方框滤波回调函数
void CallbackBoxFilter(int, void*)
{
boxFilter(SrcImg, boxFilterDstImg, -1, Size(boxFilterValue+1, boxFilterValue+1));//方框滤波函数
namedWindow("方框滤波效果图");
imshow("方框滤波效果图", boxFilterDstImg);
}
//均值滤波回调函数
void CallbackBlur(int, void*)
{
blur(SrcImg, blurDstImg, Size(blurValue + 1, blurValue + 1));//均值滤波函数
namedWindow("均值滤波效果图");
imshow("均值滤波效果图", blurDstImg);
}
//高斯滤波回调函数
void CallbackGaussianBlur(int, void*)
{
GaussianBlur(SrcImg, GaussianBlurDstImg, Size(GaussianBlurValue *2+ 1, GaussianBlurValue*2 + 1), 0, 0);//高斯滤波函数
namedWindow("高斯滤波效果图");
imshow("高斯滤波效果图",GaussianBlurDstImg);
}
//中值滤波回调函数
void CallbackMeddianBlur(int, void*)
{
medianBlur(SrcImg, meddianBlurDstImg, meddianBlurValue*2+1);
namedWindow("中值滤波效果图");
imshow("中值滤波效果图", meddianBlurDstImg);
}
//双边滤波回调函数
void CallbackBilateralBlur(int, void*)
{
//参数三:int d 表示在过滤过程中每个像素邻域的直径
//参数四:double sigmaColor 颜色空间滤波器的sigma值。
//参数四:这个参数的值越大,就表明该像素邻域内有更宽广的颜色会被混合到一起,产生较大的半相等颜色区域。
//参数五:double类型的sigmaSpace 坐标空间中滤波器的sigma值,坐标空间的标注方差。
//参数五:他的数值越大,意味着越远的像素会相互影响,从而使更大的区域足够相似的颜色获取相同的颜色。
//参数五:当d>0,d指定了邻域大小且与sigmaSpace无关。否则,d正比于sigmaSpace。
bilateralFilter(SrcImg, bilateralBlurDstImg, bilateralBulrValue, bilateralBulrValue * 2, bilateralBulrValue / 2);
namedWindow("双边滤波效果图");
imshow("双边滤波效果图", bilateralBlurDstImg);
}
*********************2016.8.18***********************
@滤波:线性滤波与非线性滤波
线性滤波:
方框滤波——boxblur函数
均值滤波(邻域平均滤波)——blur函数
高斯滤波——GaussianBlur函数
非线性滤波:
中值滤波——medianBlur函数
双边滤波——bilateralFilter函数
@常见的滤波器
允许低频率通过的低通滤波器。
允许高频率通过的高通滤波器。
允许一定范围频率通过的带通滤波器。
阻止一定范围频率通过并且允许其它频率通过的带阻滤波器。
允许所有频率通过、仅仅改变相位关系的全通滤波器。
@值得注意的
滤波≠模糊!!!!!
滤波可分低通滤波和高通滤波两种。而高斯滤波是指用高斯函数作为滤波函数的滤波操作,至于是不是模糊,要看是高斯低通还是高斯高通,低通就是模糊,高通就是锐化。
其实说白了是很简单的,对吧:
高斯滤波是指用高斯函数作为滤波函数的滤波操作。
高斯模糊就是高斯低通滤波。
@图像高低频概念
图像的高低频是对图像各个位置之间强度变化的一种度量方法.
低频分量:主要对整副图像的强度的综合度量.
高频分量:主要是对图像边缘和轮廓的度量.
变化越尖锐的地方高频频谱越多,图像细节就是变化尖锐的地方
高反差也一样,它变化很快,过渡区很小,相当于变化尖锐。
深灰到白的颜色变化比浅灰到白要大,颜色过渡更尖锐,高频分量也更多。
@图像深度
我们把计算机存储单个像素点所用到的bit为称之为图像的深度.一般图片是8bit(位)的,则深度是8.
@基本单位不要混
8bit=1Byte=1B
bit->Byte(B)->KB->MB->GB.
*********************2016.8.17***********************
@关于openCV中用createTrackbar调亮度对比度源代码
#include
#include
//#include
#include
using namespace std;
using namespace cv;
//全局变量,因为回调函数和主函数都要用到。
Mat SrcImg;
Mat DstImg;
int ContrastValue = 50;//对比度初值
int BrightValue = 50;//亮度初值
//声明回调函数
void CallbackContrastBright(int, void*);
//主函数
int main(int *argc, char *argv[])
{
SrcImg = imread("FIFA.png");
if (!SrcImg.data)
{
printf("读取图片失败!请尝试检查!\n");
return false;
}
//初始化目标图像
DstImg = Mat::zeros(SrcImg.size(), SrcImg.type());
//调用回调函数
//第一个参数为目标数值,第二个参数因为目标数值为全局变量,所以为0.
CallbackContrastBright(ContrastValue, 0);
CallbackContrastBright(BrightValue, 0);
//createTrackbar(Trackbar名称,Trackbar附着的窗口名称,目标数值的初值,目标数值的最大值,回调函数)
//createTrackbar 的最后一个参数默认为0,因为目标数值(ContrastValue&BrightValue)为全局变量。
//定义的回调函数CallbackContrastBright必须为void Foo(int,void*)格式
createTrackbar("对比度", "效果图", &ContrastValue, 200, CallbackContrastBright);
createTrackbar("亮度", "效果图", &BrightValue, 100, CallbackContrastBright);
namedWindow("原图", WINDOW_AUTOSIZE);
imshow("原图", SrcImg);
waitKey();
return true;
}
//定义的回调函数CallbackContrastBright必须为void Foo(int,void*)格式
//typedef Vec Vec2b;
//Vec2b---表示每个Vec2b对象中,可以存储2个char(字符型)数据
//Vec3b---表示每一个Vec3b对象中,可以存储3个char(字符型)数据,比如可以用这样的对象,去存储RGB图像中的
//Vec4b---表示每一个Vec4b对象中,可以存储4个字符型数据,可以用这样的类对象去存储---4通道RGB+Alpha的图
//二维图像的遍历像素方法如下(详情查看Mat::at)
//Mat H(100, 100, CV_64F);
// for (int i = 0; i < H.rows; i++)
// for (int j = 0; j < H.cols; j++)
// H.at(i, j) = 1. / (i + j + 1);
void CallbackContrastBright(int,void*)
{
//利用3个循环遍历图像中的所有像素
for (int y = 0; y < SrcImg.rows; ++y)
{
for (int x = 0; x < SrcImg.cols; ++x)
{
for (int c = 0; c < 3; ++c)
{
//亮度对比度调节理论依据:g(i,j)=a*f(i,j)+b(其中a为对比度,b为亮度)
//我们的轨迹条一般取值都会整数
//所以在这里我们可以,将其代表对比度值的ContrastValue参数设为0到200之间的整型,在最后的式子中乘以一个0.01
//因为我们的运算结果可能超出像素取值范围(溢出),还可能是非整数(如果是浮点数的话)
//所以我们要用saturate_cast对结果进行转换,以确保它为有效值。
//saturate in the name means that when the input value v is out of the range of the target type
//the result is not formed just by taking low bits of the input, but instead the value is clipped.For example :
//uchar a = saturate_cast(-100); // a = 0 (UCHAR_MIN)
//short b = saturate_cast(33333.33333); // b = 32767 (SHRT_MAX)
DstImg.at(y, x)[c]= saturate_cast((ContrastValue*0.01)*SrcImg.at(y,x)[c]+BrightValue);
}
}
}
namedWindow("效果图", WINDOW_AUTOSIZE);
imshow("效果图", DstImg);
}
@关于Vec3b,Vec2b,Vec2s等的概念及用法
概念:typedef Vec
【1】Vec2b—表示每个Vec2b对象中,可以存储2个char(字符型)数据
【2】Vec3b—表示每一个Vec3b对象中,可以存储3个char(字符型)数据,比如可以用这样的对象,去存储RGB图像中的
【3】Vec4b—表示每一个Vec4b对象中,可以存储4个字符型数据,可以用这样的类对象去存储—4通道RGB+Alpha的图
用法:例如遍历一图像:
DstImg.at<Vec3b>(y, x)[c]= saturate_cast<uchar>((ContrastValue*0.01)*SrcImg.at<Vec3b>(y,x)[c]+BrightValue);
`
*********************2016.8.16***********************
@assertion failed错误
在debug模式下报assertion failed错误,请教是什么原因,在return true出现断言,release可以运行?
解决方法:这种情况下一般都是项目属性debug和release的都配置在一块了,debug模式下只要debug的库,release模式下只要release的库,应该就可以
*********************2016.8.12***********************
Mat::Mat(……..)的众多构造函数有很多,很多都涉及到类型 type。type可以是 CV_8UC1,CV_16SC1,…,
CV_64FC4 等。里面的 8U 表示 8 位无符号整数, 16S 表示 16 位有符号整数, 64F
表示 64 位浮点数(即 double 类型); C 后面的数表示通道数,例如 C1 表示一个
通道的图像, C4 表示 4 个通道的图像,以此类推
*********************2016.8.10***********************
@最简单的OpenCV程序,读取与显示图片
using namespace cv;
int main()
{
Mat pic = imread("fengjing.jpg");
namedWindow("风景", WINDOW_NORMAL);
imshow("风景",pic);
waitKey(10000);
return 0;
}
*********************2016.8.9***********************
@opencv环境配置问题:一直有未经处理的中断异常
其实,在显示了文件的扩展名后才发现问题:本来是1.jpg的图片结果成了1.jpg.jpg了,因此,在出现上述异常时,不仅仅要考虑到是配置问题,还有可能仅仅就是扩展名没有填写正确。当然,保险的做法是不要隐藏电脑的文件扩展名!!!