影像处理作业心得:直方图以及直方图均化
1.
练习:
1.1 控件
做这个之前先练习了一下builder里面各个控件的使用,遇到了些小问题,如tabsheet内部控件的归属一开始用拉的,则总会默认拉到form中,使得运行时任意一个tabsheet中都看到该控件,这个时候有两个解决方法(经过尝试得出):
l 删掉该控件,重新选择控件,用点击的方式,点到tabsheet中则可。
l 在builder的structure视图中(见图1.1)使用拉的方式,将控件拉回到tabsheet中。
1.2 简单处理
先尝试了自己做一些简单的操作如打开文件、保存文件、显示单个通道(红、绿、蓝、灰阶)、负片、鼠标滑过rgb值显示以及画图(矩形,线条)
Figure 1.1
2.
直方图与直方图均化
2.1直方图
实现阐述:
直方图的算法就是scan图片的像素值分别统计R、G、B各个色阶数目保存在数组中,再利用所得数据画线则可,算法简明。同样的,累积数据只要单独处理头值[Channel][0]之后用当前数目加上上一个值的累积数则可。
直方图中要常用到的数据刚好是label显示中的四种数据(显示数据时要根据滑鼠的位置反向推导出通道值和色阶值,计算一下则可),Pixel Count, Pixel Ratio, Cumulative Pixel Count, Cumulative Pixel Ratio
(便于滑鼠经过显示数据mousemove事件的编写)
对于这四种数据考虑到会常用,则选择都用数组来存储,大小均为[3][256]。
四个数据的统计在一个事件里完成,也就是菜单栏的histogram选项点击事件。直方图画图函数是直接把三个通道值画出,在后面写到checkbox的处理时,就会代码重用性降低,因此改写了代码,画直方图的函数改为传进参数channel(所需画的通道),再根据通道来画红、蓝、绿。修改原直方图程式为调用三次画图程式,分别红蓝绿,三个的勾选改变事件只要关联其中一个勾选改变程式就可以,如Red勾选改变,在处理程式里面都要判断选择的是简单Histogram还是Cumulative的,继而判断三个颜色的,再执行相应操作。这样子代码重用性加强,也便于在调整UpDown的时候根据勾选重画直方图。
四个数据的统计在一个事件里完成,也就是菜单栏的histogram选项点击事件。直方图画图函数是直接把三个通道值画出,在后面写到checkbox的处理时,就会代码重用性降低,因此改写了代码,画直方图的函数改为传进参数channel(所需画的通道),再根据通道来画红、蓝、绿。修改原直方图程式为调用三次画图程式,分别红蓝绿,三个的勾选改变事件只要关联其中一个勾选改变程式就可以,如Red勾选改变,在处理程式里面都要判断选择的是简单Histogram还是Cumulative的,继而判断三个颜色的,再执行相应操作。这样子代码重用性加强,也便于在调整UpDown的时候根据勾选重画直方图。
一开始看到教学部落格里面说:
---“在 Histogram Page 中, 直方圖是用一張高 256 寬 768 的圖形來繪製, 寬之所以為 768 的原因是需要顯示紅、綠、藍等三個色彩的直方圖, 每個色彩需要 256 條直線, 一共 256*3=768 條直線繪製完整的直方圖。”
自己就立马认为是R、G、B分别用0~255,256~511、512~768来显示,因此显示的是三个通道的分部分开的直方图,这样出来的效果(如图2.1.1)比较单一,没那么好看。可是继续看到看到部落格直方图分部都是占满整个横轴(图2.1.2)就在思考三个颜色分开为什么会重叠并且连续,在这上面好像卡了一下,但先放着继续做了后面的分析,等到星期二晚问了老师才知道是错开显示,也就是R、G、B、R、G、B这样,因此只要修改函数里循环处理内容的位置索引就可以了。
如下
之前
|
ImageHistogram->Canvas->MoveTo(j
+ i*255, pHeight); ImageHistogram->Canvas->LineTo(j
+ i* 255, (int)YValue);
|
之后
|
ImageHistogram->Canvas->MoveTo(3
* j + i, pHeight); ImageHistogram->Canvas->LineTo(3
* j + i, (int)YValue);
|
Figure 2.1.1
Figure 2.1.2
2.2 直方图均化
均化就是将原本密集的直方分布分散,说白了就是增大对比度。简单处理原理为:色阶值 = 原色阶值*累积比例。
设图片大小M*N,建表3*M*N:
一开始自己写的是读取图片各个像素点的RGB值并且转换为新的均化后的值存在M*N的矩阵里面,然后再在结果图中一个点一个点去写,这样子效率极低,而且出错率高,以至于均化运行的时候出来的结果多样,出现过以下情况(原图为老师提供的鸟图)
这种实现比较繁杂,因为要是3*M*N的矩阵,则要用指针动态分配数组3*M*N,然后之后使用的时候索引要注意一维数组当做二维数组的使用,容易算错索引到时index
out of range.解决了问题之后,给出了一个奇怪的结果,也许是不小心灰阶处理了。
一开始以为看得到轮廓就是写好了,后来调试的时候觉得色阶处理有问题,则重新思考了色阶的数据结构。因为同一个色阶n转换之后的值m是一样的,因此改用了[3][256]重新作为结果数组存储数值,在scan图片的时候找出对应的更改后的值再赋值。结构相对小,处理比较简单,所以修改之后运行效果很快出来,达到预期效果。由于是另外一张图片显示结果,所以声明两个byte的指针,一个用于原图分析原色阶,通过数组去获得修改后色阶,改写另一个结果图的色阶。
for(i = 0 ; i
<ImageOrigin->Picture->Height; i ++ )
{
bptr
= (Byte *)ImageProcess->Picture->Bitmap->ScanLine[i];
obptr
= (Byte *)ImageOrigin->Picture->Bitmap->ScanLine[i];
for(j
= 0 ; j <ImageProcess->Picture->Width; j ++)
{
for(k = 0 ; k < Channel; k ++)
bptr[
j*3 + k ] = EqualizationMatrix[k][obptr[ j*3 + k ]];
}
}
|
2.3 直方图均化程度选择
给出min,max,将原直方图疏松到min,max之间,而不是原来的0到255
先找到了Tracebar控件去获得用户输入,没找到两头的,就用两个来分别获得min、max。
将色阶修改算法改一点,为value = min + (Rvalue * cdf)* (max - min) + 0.5
新的程式码如下:
for(i = 0 ; i < Channel ; i ++)
{
for(j = 0 ; j < 256;
j++ )
{
EqualizationMatrix[i][j]
= EqualMin + (int)(CPCRatio[i][j]/100.0 * (EqualMax -EqualMin) + 0.5);
}
//原式EqualizationMatrix[i][j] = (int)(CPCRatio[i][j]/100.0 * 255.0 +
0.5);
} |
结果图展示
原图:
普通直方图:
红:
|
绿:
|
蓝:
|
红绿:
|
红蓝:
|
绿蓝:
|
红绿蓝:
|
红绿蓝ButtonUp:
|
红绿蓝ButtonDown:
|
累积图:
红:
|
绿:
|
蓝:
|
红绿:
|
红蓝:
|
绿蓝:
|
红绿蓝:
|
红绿蓝ButtonUp:
|
红绿蓝ButtonDown:
|
简易均化效果图:
可以看出,花的均化效果跟原图作比较,没有很大的差别,原图的直方图分部已经布满0-255了,所以均化后效果不会特别突出。
测试均化效果:
原图:
直方图:
简易均化(默认0-255):
均化后直方图:
此时鸟均化后的图明显比原图对比大,颜色明显,而原图直方分布比较密集,集中在值比较小的区域,在均化之后图片的直方图分布已经扩展到整个0-255,对比度大大增强,效果明显。
因此,直方均化比较适用于直方分布比较密集,对比度低的图片,不适合比较平坦的直方图。
根据以上结论,均化自己拍摄的图片:
原图:
均化效果:
可以清楚看到为浴室
调整均化程度:
调整output level(滑动tracebar)为min-max
0-82:
直方图:0-159:
70-255:
总的来说,虽然完成所有功能的实现,但完成这次作业首先花了一部分时间熟悉环境,在不断的编写过程中会出现比较粗心的错误,如变量名搞错之类的,小错误造成大差别。编写的方法不断修改,也许开始做作业前欠充分的考虑,导致方法未能一开始达到理想,而使用的数据结构也是,应多思考实现的算法高效性,如M*N矩阵。下次作业谨记这次教训。
沒有留言:
張貼留言