2009年10月28日 星期三

泛用Cv函式之規劃

 
若圖檔格式不同,輸出圖像變換結果時,就要做一堆前提驗證,例如:
//將 in 圖像的亮度乘上 ratio 後存入 out 中

void adjust_brightness (IplImage* in, IplImage* out, float ratio)
{
    if (in->width  != out->width ||
        in->height != out->height)
        ERROR_MSG_("來源圖像與目的圖像的寬高不相等!");

    int x,y, x0;
    int srcStep = in-> nChannels; 
    int dstStep = out->nChannels; 
    int h       = in-> height; 
    uchar* src  = (uchar*) in-> imageData;
    uchar* dst  = (uchar*) out->imageData;


    if (srcStep > dstStep)
        ERROR_MSG2_("目的圖像的 channel 太小: %d", dstStep);

    if (srcStep != 1 && srcStep != 3)
        ERROR_MSG_("來源圖像的 channel 需為 1 或 3");

    if (dstStep != 1 && dstStep != 3)
        ERROR_MSG_("目的圖像的 channel 需為 1 或 3");


    if (srcStep == dstStep) 
    {
        int step = in->nChannels; 
        int W    = in->widthStep;
        int xw   = in->width * step;
    
        if (step == 1) {                            //灰階圖
            for (y=0; y<h; y++, src+=W, dst+=W)
                for (x=0; x<xw; x+=step)   
                    dst[x] = uchar (src[x] * ratio);
        }
        else                                        //24 bits 圖
            for (y=0; y<h; y++, src+=W, dst+=W)
                for (x=0; x<xw; x+=step) {  
                    dst[x+0] = uchar (src[x+0] * ratio);
                    dst[x+1] = uchar (src[x+1] * ratio);
                    dst[x+2] = uchar (src[x+2] * ratio);
                }          
    } else {
        int srcW = in-> widthStep;     
        int dstW = out->widthStep; 
        int xw   = out->width * dstStep;

        for (y=0; y<h; y++, src+=srcW, dst+=dstW)
            for (x0=x=0; x<xw; x+=dstStep, ++x0) {  
                dst[x+0] = uchar (src[x0] * ratio);
                dst[x+1] = uchar (src[x0] * ratio);
                dst[x+2] = uchar (src[x0] * ratio);
            }     
    }
}
設計這些個函式時,有如下幾種規劃:

1. 拿時空換取便利,將所有圖像正規化到同一種格式,例如:32 bits。
2. 寫一個像上面的通用函式,並驗證所有可能的狀況。
3. 引入一個驗證層,將前提檢驗責任交給它:
    由於各種可能狀況可事先列出,每種狀況即為驗證層樣板的一個 instance,
    對每種影像處理函式選定合適的 instance 即可。
4. 限定影像處理函式只接受他們能處理的影像格式,
    對於無法處理的格式,在編譯期強迫程式師事先要做好轉換。

底下是另一個例子,限制 channel 對應只能是
1 -> 1
1 -> 3
3 -> 3
//將 in 的 ROI 拷貝到 out 的 ROI

void copy_image_ROI (IplImage* in, IplImage* out)
{
    CvRect srcRect = cvGetImageROI (in);
    CvRect dstRect = cvGetImageROI (out);

    if (srcRect.width  != dstRect.width ||
        srcRect.height != dstRect.height)
        ERROR_MSG_("來源圖像與目的圖像的 ROI 寬高不相等!");

    int x,y, x0;
    int srcStep = in ->nChannels; 
    int dstStep = out->nChannels; 
    int srcW    = in ->widthStep;
    int dstW    = out->widthStep;
    int h       = srcRect.height; 
    char* src   = in ->imageData+ srcRect.y* srcW+ srcRect.x* srcStep;
    char* dst   = out->imageData+ dstRect.y* dstW+ dstRect.x* dstStep;


    if (srcStep > dstStep)
        ERROR_MSG2_("目的圖像的 channel 太小: %d", dstStep);

    if (srcStep != 1 && srcStep != 3)
        ERROR_MSG_("來源圖像的 channel 需為 1 或 3");

    if (dstStep != 1 && dstStep != 3)
        ERROR_MSG_("目的圖像的 channel 需為 1 或 3");


    if (srcStep == dstStep) 
    {
        int xw = srcRect.width * srcStep;    
        if (srcStep == 1)                           //灰階圖
            for (y=0; y<h; y++, src+=srcW, dst+=dstW)
                for (x=0; x<xw; ++x)   
                    dst[x] = src[x];
        else                                        //24 bits 圖
            for (y=0; y<h; y++, src+=srcW, dst+=dstW)
                for (x=0; x<xw; x+=3) {  
                    dst[x+0] = src[x+0];
                    dst[x+1] = src[x+1];
                    dst[x+2] = src[x+2];
                }          
    } else {
        int xw = dstRect.width * dstStep;
        for (y=0; y<h; y++, src+=srcW, dst+=dstW)
            for (x0=x=0; x<xw; x+=3, ++x0) {  
                dst[x+0] = src[x0];
                dst[x+1] = src[x0];
                dst[x+2] = src[x0];
            }     
    }
}
The Mythical Man-Month:
- 好的設計,既不可單獨偏重功能性,也不可只偏重簡單性。

沒有留言:

張貼留言