2014-01-08 32 views
0

我想模糊圖像,而不使用像blur()一樣的opencv預定義函數。我正在使用標準平均值而不是加權平均值。這裏是我的代碼,但結果仍然與輸入圖像相同。這是3x3。模糊圖像由標準的平均值C++

IplImage* img = cvLoadImage(argv[1]); 
    IplImage* dst = cvCloneImage(img); 

    height = img->height; 
    width = img->width; 
    step = img->widthStep; 
    channels = img->nChannels; 
    data = (uchar *)img->imageData; 

    height2 = dst->height; // row 
    width2  = dst->width; // col 
    step2  = dst->widthStep; // size of aligned image row in bytes 
    channels2 = dst->nChannels; 
    dstData  = (uchar *)dst->imageData; 
    int total = 0; 

    //blur 
    for (i = 0; i < height; i++) { 
     for (j = 0; j < width; j++) {   
      for (x = 0; x <= 2; x++) 
       for (y = 0; y <= 2; y++) 
        total =(data[x-1,y-1]+data[x-1,y]+data[x-1,y+1]+ 
          data[x,y-1]+data[x,y]+data[x,y+1]+ 
          data[x+1,y-1]+data[x+1,y]+data[x+1,y+1])/9; 
        dstData[i,j] = total; 
        } 
      } 

我想我的問題是在這一個

     total =(data[x-1,y-1]+data[x-1,y]+data[x-1,y+1]+ 
         data[x,y-1]+data[x,y]+data[x,y+1]+ 
         data[x+1,y-1]+data[x+1,y]+data[x+1,y+1])/9; 
         dstData[i,j] = total; 

什麼可以做?

+0

逗號運算符會導致一個非常常見的錯誤:'data [x-1,y-1]'等於'data [y-1]'。多維數組由一個線性內存塊表示,因此您需要類似'data [x-1 +(y-1)* width]'(您確定像素是由單個字節表示的嗎?) ,您應該檢查邊界,因爲當x = 0時,訪問像素(x-1,y)無效。 – riv

+0

在opencv圖像的行末端可能會有填充,因此請使用widthStep跳轉到下一行。考慮圖像數據類型,可能與uchar不同!考慮圖像通道,你可能不想在不同的通道中模糊。如果用戶傳遞RGB圖像,則您的濾鏡會一起模糊RGB。 OpenCv以形式012012012012(數字表示通道ID)存儲多通道圖像 – dousin

+0

看起來像問題是您總是調用同一個區域進行模糊處理:try'total =(data [(i-1 +(j-1))* width ] ..../9;'但是正如@riv所提到的那樣,您需要檢查邊界錯誤,以便數組不會嘗試從負數位置獲取數據。 – GMasucci

回答

1

一個完整的程序,顯示如何做到這一點。你有幾個錯誤,1)不正確的像素訪問(http://www.comp.leeds.ac.uk/vision/opencv/iplimage.html)。 2)模糊循環是錯誤的,你總是從左上角的3x3角獲取數據。如果像素訪問是正確的,你應該在dst中獲得一個不變的圖像。

另一件事是你還需要照顧通道信息,程序通過閱讀單通道圖像旁路。否則,你需要做的模糊對每個通道

#include <opencv2/opencv.hpp> 


int main(int argc, char* argv[]) 
{ 

    IplImage* img = cvLoadImage("c:/data/2.jpg",0); 
    IplImage* dst = cvCloneImage(img); 
    int height,width,step,channels; 
    int height2,width2,step2,channels2; 

    height = img->height; 
    width = img->width; 
    step = img->widthStep; 
    channels = img->nChannels; 
    uchar* data = (uchar *)img->imageData; 

    height2 = dst->height; // row 
    width2  = dst->width; // col 
    step2  = dst->widthStep; // size of aligned image row in bytes 
    channels2 = dst->nChannels; 
    uchar* dstData  = (uchar *)dst->imageData; 
    int total = 0; 
    int i,j,x,y,tx,ty; 
    //blur 
    for (i = 0; i < height; i++) { 
     for (j = 0; j < width; j++) { 
      int ksize=3; 
      total=0; 
      for (x = -ksize/2; x <=ksize/2; x++) 
       for (y = -ksize/2; y <=ksize/2; y++) 
       { 
        tx=i+x; 
        ty=j+y; 
        if(tx>=0&&tx<height && ty>=0 && ty<width) 
        { 
         total+=data[tx*step+ty]; 
        } 
       } 

      dstData[i*step+j] = total/ksize/ksize; 
     } 
    } 
    cvShowImage("img",img); 
    cvShowImage("dst",dst); 
    cvWaitKey(0); 
} 
+0

感謝您的回答,並感謝您澄清我的錯誤。太棒了! – Nhiz

+0

我試圖通過改變5的ksize爲5和除數爲3,但我得到了3x3的較暗圖像。我應該改變什麼? – Nhiz

+0

如果性能是一個問題,你應該避免一堆如果分支內'for'循環 - 跳過圖像bordres上的ksize/2行和列,然後執行計算。如果需要計算所有像素,分別計算邊界行和列 - 帶來的好處是,您可以使用正確的比例因子邊界像素 – dousin

0

假設像素超範圍分配0,下面的代碼應該是你想要的。核心是my_average函數,它計算中心在ij的3 * 3窗口的平均值。

for (i = 0; i < height; i++) 
    for (j=0; j < width; j++) 
     dstData[i*width+j] = my_average(data, i, j, height, width); 

double my_average(uchar * data, int y, int x, int height, int width) { 
    double sum = 0; 
    if(x-1 >= 0 && y-1 >= 0) { 
     sum += data[(y-1)*width + x-1]; 
    } 
    if(x-1 >= 0) { 
     sum += data[y*width + x-1]; 
    } 
    if(x-1 >= 0 && y+1 < height) { 
     sum += data[(y+1)*width + x-1]; 
    } 
    if(y-1 >= 0) { 
     sum += data[(y-1)*width + x]; 
    } 
    sum += data[y*width + x]; 
    if(y+1 < height) { 
     sum += data[(y+1)*width + x]; 
    } 
    if(x+1 < width && y-1 >= 0) { 
     sum += data[(y-1)*width + x+1]; 
    } 
    if(x+1 < width) { 
     sum += data[y*width + x+1]; 
    } 
    if(x+1 < width && y+1 < height) { 
     sum += data[(y+1)*width + x+1]; 
    } 

    return sum/9; 
}