2008年7月11日 星期五

資料結構操作與運算-IplImage資料結構操作(2)

這邊就介紹演算法實作讓程式碼最簡潔的的方式啦,跟前面直接存取不同,這邊是用到OpenCV的內部函式去設計的,因此程式碼看起來簡潔有力,也不需要特意去算通道數及研究一維陣列如何存取,這裡的實作為二值化的程式設計(Image Thresholding),也就是圖形的結果不是0就是255,甚至可以將它存入IPL_DEPTH_1U參數的製作.

IplImage資料結構二值化實作
#include <cv.h>
#include <highgui.h>
#include <stdio.h>


double Red[512][384];
double Green[512][384];
double Blue[512][384];
double Gray[512][384];

int main()
{
    int Height;
    int Width;
    int Threshold=64;
    IplImage *Image1,*Image2;
    Image1=cvLoadImage("bower.jpg",1);
    Image2=cvCloneImage(Image1);

    CvScalar Scalar1;

    Height=cvGetDimSize(Image1,0);
    Width=cvGetDimSize(Image1,1);

    /*Load Image RGB Values*/
    
for(int i=0;i<Height;i++)
    {
        for(int j=0;j<Width;j++)
        {
            Scalar1=cvGet2D(Image1,i,j);
            Blue[i][j]=Scalar1.val[0];
            Green[i][j]=Scalar1.val[1];
            Red[i][j]=Scalar1.val[2];
        }
    }

    /*Implement Algorithms*/
    for(int i=0;i<Height;i++)
    {
        for(int j=0;j<Width;j++)
        {
            Gray[i][j]=0.299*Red[i][j] + 0.587*Green[i][j] + 0.114*Blue[i][j];
            if(Gray[i][j]<Threshold)
            {
                Red[i][j]=0;
                Green[i][j]=0;
                Blue[i][j]=0;
            }
            else
            {
                Red[i][j]=255;
                Green[i][j]=255;
                Blue[i][j]=255;
            }
        }
    }

    /*Save Image RGB Values*/
    for(int i=0;i<Height;i++)
    {
        for(int j=0;j<Width;j++)
        {
            Scalar1=CV_RGB(Red[i][j],Green[i][j],Blue[i][j]);
            cvSet2D(Image1,i,j,Scalar1);
        }
    }


    cvNamedWindow("Bower Thresholding",1);
    cvShowImage(Bower Thresholding",Image1);
    cvNamedWindow("Bower",1);
    cvShowImage("Bower",Image2);
    cvWaitKey(0);
}

執行結果:


上面的程式使用了cvCloneImage()複製了一份原始圖片,而RGB演算法的使用上相較之下已經比imageData的方式簡單許多了,而imageData也因此被包在下一層做運算了,這邊除了用到了前面所提到的cvGet2D()跟cvSet2D()做運算,還設計了灰階的轉換,而對灰階做一個門檻值非黑即白就是二值化的製作了跟前面那篇"GUI介面的製作-Trackbar製作"的cvThreshold()是同一個演算法,而中間/*Implement Algorithms*/的部份,就可以自由的存取RGB值了!

這裡再提到幾個重要的部份,這部份做存取RGB值的操作,會有許多的問題及瓶頸,今天假設要存取的圖片是1000*1300大小的維度,使用一般的二維陣列存取RGB值一定會爆掉,因為RGB陣列的宣告是存在靜態Stack空間的,對編譯器而言,Stack空間是有限的,而在編譯的一開始編譯器就設定了Stack空間的大小,因此解決的方法,除了去編譯器的環境設定下調整Stack空間的大小,要不然就是要使用二維動態陣列了,而且使用動態二維陣列,也可以在不曉得圖片大小的情況下實作二維陣列,動態陣列屬於Heap的空間,當Heap空間不夠的時候會被分頁替換,對Heap空間來講,其實是沒上限的,但在使用上Heap會比Stack慢,而CvMat,IplImage其實就是一種Heap的實作之一.簡而言之,資料結就是使用到Heap空間.

另一個部分是分頁錯誤的問題,今天假如上面的程式碼,寬在第一層for迴圈,高在第二層for迴圈,會嚴重的影響程式的效能,因為他中間做了更多次的分頁替換,對for迴圈來講,每做一次就會錯一次,對一個二維陣列的存取來說,不該有這種情形發生,詳細的說明可以去參考作業系統原理分頁替換的部分.

cvCloneImage()
複製一份完整的IplImage資料結構圖形及設定
cvCloneImage(IplImage資料結構)



3 意見:

Unknown 提到...

hi,yester
代码中写错了:
cvNamedWindow("Bower Thresholding",1);
cvShowImage(Bbower Thresholding",Image1);
我改了20分钟,才发现拼写错了

wa114040@gmail.com 提到...

感謝指正~

匿名 提到...

您好,為什麼我執行出來結果
處理後的圖會有部分是重複的呢??

Copyright 2008-2009,yester