2012年10月18日 星期四

01362512 林贝静 直方图以及直方图均化心得

影像处理作业心得:直方图以及直方图均化

1.       练习:
1.1 控件
做这个之前先练习了一下builder里面各个控件的使用,遇到了些小问题,如tabsheet内部控件的归属一开始用拉的,则总会默认拉到form中,使得运行时任意一个tabsheet中都看到该控件,这个时候有两个解决方法(经过尝试得出)
l  删掉该控件,重新选择控件,用点击的方式,点到tabsheet中则可。
l  builderstructure视图中(见图1.1)使用拉的方式,将控件拉回到tabsheet中。
经过以上两种方法则可将控件归属回tabsheet
1.2 简单处理
先尝试了自己做一些简单的操作如打开文件、保存文件、显示单个通道(红、绿、蓝、灰阶)、负片、鼠标滑过rgb值显示以及画图(矩形,线条)

Figure 1.1

2.       直方图与直方图均化
2.1直方图
实现阐述:
    直方图的算法就是scan图片的像素值分别统计RGB各个色阶数目保存在数组中,再利用所得数据画线则可,算法简明。同样的,累积数据只要单独处理头值[Channel][0]之后用当前数目加上上一个值的累积数则可。
直方图中要常用到的数据刚好是label显示中的四种数据(显示数据时要根据滑鼠的位置反向推导出通道值和色阶值,计算一下则可),Pixel Count, Pixel Ratio, Cumulative Pixel Count, Cumulative Pixel Ratio (便于滑鼠经过显示数据mousemove事件的编写)
    对于这四种数据考虑到会常用,则选择都用数组来存储,大小均为[3][256]
    四个数据的统计在一个事件里完成,也就是菜单栏的histogram选项点击事件。直方图画图函数是直接把三个通道值画出,在后面写到checkbox的处理时,就会代码重用性降低,因此改写了代码,画直方图的函数改为传进参数channel(所需画的通道),再根据通道来画红、蓝、绿。修改原直方图程式为调用三次画图程式,分别红蓝绿,三个的勾选改变事件只要关联其中一个勾选改变程式就可以,如Red勾选改变,在处理程式里面都要判断选择的是简单Histogram还是Cumulative的,继而判断三个颜色的,再执行相应操作。这样子代码重用性加强,也便于在调整UpDown的时候根据勾选重画直方图。

一开始看到教学部落格里面说:
---“在 Histogram Page , 直方圖是用一張高 256 768 的圖形來繪製, 寬之所以為 768 的原因是需要顯示紅、綠、藍等三個色彩的直方圖, 每個色彩需要 256 條直線, 一共 256*3=768 條直線繪製完整的直方圖。”
自己就立马认为是RGB分别用0~255,256~511512~768来显示,因此显示的是三个通道的分部分开的直方图,这样出来的效果(如图2.1.1)比较单一,没那么好看。可是继续看到看到部落格直方图分部都是占满整个横轴(图2.1.2)就在思考三个颜色分开为什么会重叠并且连续,在这上面好像卡了一下,但先放着继续做了后面的分析,等到星期二晚问了老师才知道是错开显示,也就是RGBRGB这样,因此只要修改函数里循环处理内容的位置索引就可以了。
如下
之前
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 直方图均化程度选择
给出minmax,将原直方图疏松到minmax之间,而不是原来的0255
先找到了Tracebar控件去获得用户输入,没找到两头的,就用两个来分别获得minmax

将色阶修改算法改一点,为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

直方图:

139-255
直方图:

255-0:(min>max

直方图:

总的来说,虽然完成所有功能的实现,但完成这次作业首先花了一部分时间熟悉环境,在不断的编写过程中会出现比较粗心的错误,如变量名搞错之类的,小错误造成大差别。编写的方法不断修改,也许开始做作业前欠充分的考虑,导致方法未能一开始达到理想,而使用的数据结构也是,应多思考实现的算法高效性,如M*N矩阵。下次作业谨记这次教训。

沒有留言:

張貼留言