天天看點

Qt 之圖像處理(八) canny算子 c++

canny算子

原理:

代碼:

QImage inputImage : 輸入圖像

QImage outputImage : 輸出圖像

BYTE bThreL : 低門檻值

BYTE bThreH : 高門檻值

bool Thinning : 是否細化

//canny算子
void MainWindow::Canny_pro(QImage *inputImage,QImage* outputImage,BYTE bThreL,BYTE bThreH,bool Thinning)
{


    int width = inputImage->width();
    int height = inputImage->height();


    QColor Color_canny,Color_X,Color_Y,Color_45,Color_135;


    QImage* pImageThreL = new QImage(width,height,QImage::Format_ARGB32);
    QImage* pImageThreH = new QImage(width,height,QImage::Format_ARGB32);
    QImage cannyImg=QImage(width,height,QImage::Format_ARGB32);
    QImage SobelImg_X=QImage(width,height,QImage::Format_ARGB32);
    QImage SobelImg_Y=QImage(width,height,QImage::Format_ARGB32);
    QImage SobelImg_135=QImage(width,height,QImage::Format_ARGB32);
    QImage SobelImg_45=QImage(width,height,QImage::Format_ARGB32);

    for(int i = 0; i<height; i++)
    {
        for(int j = 0; j<width; j++)
        {
             SobelImg_X.setPixel(j,i, qRgb(0, 0, 0));
             SobelImg_Y.setPixel(j,i, qRgb(0, 0, 0));
             SobelImg_135.setPixel(j,i, qRgb(0, 0, 0));
             SobelImg_45.setPixel(j,i, qRgb(0, 0, 0));
             cannyImg.setPixel(j,i, qRgb(0, 0, 0));
             outputImage->setPixel(j,i, qRgb(0, 0, 0));
             pImageThreL->setPixel(j,i, qRgb(0, 0, 0));
             pImageThreH->setPixel(j,i, qRgb(0, 0, 0));


        }
    }


    /*
    float sobel_x[3][3] = {{-1,-2,-1},
                         {0,0,0},
                         {1,2,1}
                        };

    float sobel_y[3][3] = {{-1,0,1},
                         {-2,0,2},
                         {-1,0,1}
                        };

    float sobel_135[3][3] = {{0,1,2},
                          {-1,0,1},
                          {-2,-1,0}
                         };

    float sobel_45[3][3] = {{-2,-1,0},
                          {-1,0,1},
                          {0,1,2}
                         };


    this->Template(inputImage,SobelImg_X,3,3,1,1,sobel_x,1);
    this->Template(inputImage,SobelImg_Y,3,3,1,1,sobel_y,1);
    this->Template(inputImage,SobelImg_135,3,3,1,1,sobel_135,1);
    this->Template(inputImage,SobelImg_45,3,3,1,1,sobel_45,1);


    */
    //梯度
    //double* MainWindow::Sobel_gradiant(QImage *image,QImage &SobelIma,int modle,bool pdouble)
    //double* angle,Amplitude = this->Sobel_gradiant(inputImage,SobelImg,0,true);

    this->Sobel_gradiant(inputImage,SobelImg_X,0,false);
    this->Sobel_gradiant(inputImage,SobelImg_Y,0,false);
    this->Sobel_gradiant(inputImage,SobelImg_45,0,false);
    this->Sobel_gradiant(inputImage,SobelImg_135,0,false);


    //最大梯度方向
    int* pbDirection = new int[width*height];
    memset(pbDirection,0,(width*height)*sizeof(int));


    //最大梯度方向并寫入最大梯度值(非極大值抑制)
    for(int i = 0; i<height; i++)
    {
        for(int j = 0; j<width; j++)
        {
            int gray = 0;

            if(QColor(SobelImg_X.pixel(j, i)).red() > gray)
            {
                gray = QColor(SobelImg_X.pixel(j, i)).red();
                pbDirection[i*width + j] = 90;
                cannyImg.setPixel(j,i,qRgb(gray, gray, gray));
            }

            if(QColor(SobelImg_Y.pixel(j, i)).red() > gray)
            {
                gray = QColor(SobelImg_Y.pixel(j, i)).red();
                pbDirection[i*width + j] = 0;
                cannyImg.setPixel(j,i,qRgb(gray, gray, gray));
            }

            if(QColor(SobelImg_45.pixel(j, i)).red() > gray)
            {
                gray = QColor(SobelImg_45.pixel(j, i)).red();
                pbDirection[i*width + j] = 45;
                cannyImg.setPixel(j,i,qRgb(gray, gray, gray));
            }

            if(QColor(SobelImg_135.pixel(j, i)).red() > gray)
            {
                gray = QColor(SobelImg_135.pixel(j, i)).red();
                pbDirection[i*width + j] = 135;
                cannyImg.setPixel(j,i,qRgb(gray, gray, gray));
            }
        }
    }

    //this->Show_Image(cannyImg);

    //pImageThreL = &SobelImg_Y;
    //pImageThreH = &SobelImg_X;


    //檢查門檻值參數
    if(bThreL > bThreH)  return ;

    if(bThreH == 0)
    {
        const int nMinDiff = 20;
        int nDiffGray;

        bThreH = 0.945 * this->DetectThreshold_pro(&cannyImg,300,nDiffGray);
        bThreL = 0.15 * bThreH;

        if(nDiffGray < nMinDiff)
        {
            return ;
        }

     }
    if(bThreL == 0)
    {
         bThreL = 0.4 * bThreH;
    }

    //将最多梯度圖像按高低值分别進行門檻值化
    this->Threshold_pro(&cannyImg,*pImageThreL,bThreL);
    this->Threshold_pro(&cannyImg,*pImageThreH,bThreH);

    //this->Show_Image(*pImageThreL);
    //this->Show_Image(*pImageThreH);



    for(int i = 1; i<height-1; i++)
    {
        for(int j = 1; j<width-1; j++)
        {

            if(QColor(pImageThreH->pixel(j, i)).red())
            {
               outputImage->setPixel(j,i,qRgb(255,255,255));


               switch (pbDirection[i*width + j]) {
               case 0:    //水準方向
                   if(QColor(pImageThreL->pixel(j+1, i)).red())
                   {
                        pImageThreH->setPixel(j+1,i,qRgb(255,255,255));
                   }
                   if(QColor(pImageThreL->pixel(j-1, i)).red())
                   {
                       pImageThreH->setPixel(j-1,i,qRgb(255,255,255));
                   }
                   break;
               case 90:
                   if(QColor(pImageThreL->pixel(j, i+1)).red())
                   {
                       pImageThreH->setPixel(j,i+1,qRgb(255,255,255));
                   }
                   if(QColor(pImageThreL->pixel(j, i-1)).red())
                   {
                       pImageThreH->setPixel(j,i-1,qRgb(255,255,255));
                   }
                   break;
               case 45:
                   if(QColor(pImageThreL->pixel(j+1, i-1)).red())
                   {
                       pImageThreH->setPixel(j+1,i-1,qRgb(255,255,255));
                   }
                   if(QColor(pImageThreL->pixel(j-1, i+1)).red())
                   {
                       pImageThreH->setPixel(j-1, i+1,qRgb(255,255,255));
                   }
                   break;
               case 135:
                   if(QColor(pImageThreL->pixel(j+1, i+1)).red())
                   {
                       pImageThreH->setPixel(j+1,i+1,qRgb(255,255,255));
                   }
                   if(QColor(pImageThreL->pixel(j-1, i-1)).red())
                   {
                       pImageThreH->setPixel(j-1, i-1,qRgb(255,255,255));
                   }
                   break;
               default:
                   break;
               }

            }

        }

    }


    //邊緣細化
    if(Thinning)
    {

    }

    *outputImage = *pImageThreH;

    delete pbDirection;
    delete pImageThreH ,pImageThreL,cannyImg,SobelImg_X,SobelImg_Y,SobelImg_45,SobelImg_135;

}