1. 程式人生 > >某些opencv函式改成c語言實現

某些opencv函式改成c語言實現

根據專案需求,需要將c++程式碼改成c語言,最後移植到DSP上。這裡記錄了opencv中的高斯濾波、大津閾值、直方圖均衡、膨脹、Sobel演算法、霍夫變換求截距六個函式改成c語言的演算法。在此記錄下。

//opencv函式改寫c
void Kernel(int size,float sigma);
void GaussianFilter (const unsigned char* pGauBlurSource);
void OtsuThreshold(const unsigned char* pOtsuSource);
void HisEqualization(const unsigned char* pHistEqualSource);
void Dilation(const unsigned char* pDilationSource);
void Sobel(const unsigned char* pSobelSource);
int HoughLines(const unsigned char* pHoughLinesSource);
void KernelSignal(int size,float sigma);
void ImprovedGaussianFilter (unsigned char* pImprovedGauBlurSource);
void ImprovedDilation(const unsigned char *pDilationSource);
void ImprovedSobel(unsigned char* pSobelSource);

//迴圈遍歷計數
int i;
int j;
int m;
int n;

//高斯濾波的模板,由高斯函式生成
float CoefArray[9]={0.106997,0.113110,0.106997,0.113110,0.119572,0.113110,0.106997,0.113110,0.106997};
//高斯濾波的模板,由高斯函式生成
const float ImprovedCoefArray[3]={0.327104,0.345791,0.327104};
const int GrayScale = 256;
int wSize = 1500;
int hSize = 180;
const int pixelSum = 270000;
const float PI = 3.141596;
//高斯濾波用到的區域性變數
unsigned char* pGauBlurResult;
int CoefArray_index = 0;
unsigned char sum = 0;
//大津閾值用到的區域性變數
int pixelCount[256];
float pixelPro[256];
int threshold;
float w0, w1, u0tmp, u1tmp, u0, u1, u, deltaMax ;
float deltatmp;
unsigned char* pOtsuSourceTmp;
unsigned char* pOtsuResult;
//直方圖均衡用到的區域性變數
unsigned char* ptr;
unsigned int tmp_hist[256];
unsigned int map[256]; //灰度對映表
int  histogram[256];//影象畫素值個數統計
int *pHistogram;      //指標定義
unsigned char* pHistEqualSourceTmp;
unsigned char* pHistResult;
//膨脹用到的區域性變數
unsigned char* pDilationResult;
int flag;
//Sobel用到的區域性變數
unsigned char* pSobelResult;
unsigned char amplitudeTmp;
unsigned char gradX;
unsigned char gradY;
//改進版的Sobel
unsigned char* pSobelSourceTmp;
float threshold = 0.6*255;
int pix;

//霍夫變換求截距用到的區域性變數
const int theta = 180;
//const int diagonalDistance = 1510;//對角線長度
int distance;
int diagonal;
int tmpDiatance;
int tmpX;
int tmpY;
int intercept;
int** linesCount;
int** linesY;

//----------高斯濾波----------//
void GaussianFilter (const unsigned char* pGauBlurSource)
{
    //邊緣不做處理
    for(i=0;i<wSize;i++)
        pGauBlurResult[i] = pGauBlurSource[i];
    for(i=(hSize-1)*wSize;i<pixelSum;i++)
        pGauBlurResult[i] = pGauBlurSource[i];
    for(i=wSize;i<(hSize-2)*wSize+1;i+=wSize)
        pGauBlurResult[i] = pGauBlurSource[i];
    for(i=wSize*2-1;i<(hSize-1)*wSize;i+=wSize)
        pGauBlurResult[i] = pGauBlurSource[i];

    for (i=1;i<hSize-1;i++)  //邊緣不處理
    {
        for (j=1;j<wSize-1;j++)
        {
            sum = 0;
            CoefArray_index = 0;
            for ( m=i-1; m<i+2; m++)
            {
                for (n=j-1; n<j+2; n++)
                {
                    sum += pGauBlurSource [ m*wSize + n] * CoefArray[CoefArray_index] ;
                    CoefArray_index++;
                }
            }
            if (sum > 255)
                sum = 255;
            pGauBlurResult[i*wSize+j] = sum;
        }
    }

}
//------------改進版高斯濾波------------//
void ImprovedGaussianFilter (unsigned char* pImprovedGauBlurSource)
{
    //邊緣不做處理
    for(i=0;i<wSize;i++)
        pGauBlurResult[i] = pImprovedGauBlurSource[i];
    for(i=(hSize-1)*wSize;i<pixelSum;i++)
        pGauBlurResult[i] = pImprovedGauBlurSource[i];
    for(i=wSize;i<(hSize-2)*wSize+1;i+=wSize)
        pGauBlurResult[i] = pImprovedGauBlurSource[i];
    for(i=wSize<<1-1;i<(hSize-1)*wSize;i+=wSize)
        pGauBlurResult[i] = pImprovedGauBlurSource[i];

    for (i=1;i<hSize-1;i++)
    {
        for (j=1;j<wSize-1;j++)
        {
            sum = pImprovedGauBlurSource[i*wSize+j-1]*ImprovedCoefArray[0]+pImprovedGauBlurSource[i*wSize+j]*ImprovedCoefArray[1]+pImprovedGauBlurSource[i*wSize+j+1]*ImprovedCoefArray[2];
            if (sum > 255)
                sum = 255;
            pGauBlurResult[i*wSize+j] = sum;
        }
    }
    for (j=1;j<wSize-1;j++)
    {
        for (i=1;i<hSize-1;i++)
        {
            sum = pGauBlurResult[(i-1)*wSize+j]*ImprovedCoefArray[0]+pGauBlurResult[i*wSize+j]*ImprovedCoefArray[1]+pGauBlurResult[(i+1)*wSize+j]*ImprovedCoefArray[2];
            if (sum > 255)
                sum = 255;
            pGauBlurResult[i*wSize+j] = sum;
        }
    }
}
//-----------大津閾值------------//
void OtsuThreshold(const unsigned char* pOtsuSource)
{
    //printf("come into OtsuThreshold\n");
    deltaMax = 0;
    threshold = 0;
    pOtsuSourceTmp = pOtsuSource;
    for (i = 0; i < GrayScale; i++)
    {
        pixelCount[i] = 0;
        pixelPro[i] = 0.0;
    }

    //統計灰度級中每個畫素在整幅影象中的個數
    for(i = 0;i < pixelSum;i++)
    {
        pixelCount[(int)(*pOtsuSourceTmp)] ++;  //將畫素值作為計數陣列的下標
        pOtsuSourceTmp++;
    }

    //計算每個畫素在整幅影象中的比例
    for (i = 0; i < GrayScale; i++)
        pixelPro[i] = (float)pixelCount[i] / pixelSum;

    //w0為背景畫素點佔整幅影象的比例;u0tmp為背景畫素點的平均灰度值;w1為前景畫素點佔整幅影象的比例;u1tmp為前景畫素點的平均灰度值;u為整幅影象的平均灰度
    //遍歷灰度級[0,255]
    for (i = 0; i < GrayScale; i++)     // i作為閾值
    {
        w0 = w1 = u0tmp = u1tmp = u0 = u1 = u = 0.0;
        deltatmp = 0.0;
        for (j = 0; j < GrayScale; j++)
        {
            if (j <= i)   //背景部分
            {
                w0 += pixelPro[j];
                u0tmp += j * pixelPro[j];
            }
            else   //前景部分
            {
                w1 += pixelPro[j];
                u1tmp += j * pixelPro[j];
            }
        }
        u0 = u0tmp/w0;
        u1 = u1tmp/w1;
        u = u0tmp + u1tmp;

        deltatmp = w0*w1*(u0-u1)*(u0-u1);//w0 * (u0 - u) * (u0 - u) + w1 * (u1 - u) * (u0 - u);

        if (deltatmp > deltaMax)
        {
            deltaMax = deltatmp;
            threshold = i;
        }
    }
    //printf("threshold=%d\n",threshold);
    //根據閾值threshold進行分割
    pOtsuSourceTmp = pOtsuSource;
    for(i = 0;i<pixelSum;i++)
    {
        if((int)*pOtsuSourceTmp > threshold)
            *pOtsuResult = 255;
        else
            *pOtsuResult = 0;
        pOtsuSourceTmp++;
        pOtsuResult++;
    }
    pOtsuResult = &Pixel_Otsu[0];

}
//--------------直方圖均衡--------------//
void HisEqualization(const unsigned char *pHistEqualSource)
{
  pHistEqualSourceTmp = pHistEqualSource;
  pHistogram = histogram;

  for(i=0;i<256;i++)
     histogram[i]=0;
  //統計各個灰度值的個數
  pHistEqualSourceTmp=pHistEqualSource;
  for(i=0;i<pixelSum;i++)//遍歷影象中的所有畫素
  {
      pHistogram=histogram;  //指標指向直方圖陣列
      pHistogram =  pHistogram + *pHistEqualSourceTmp;//取當前畫素的灰度值作為直方圖陣列的偏移量
      *pHistogram=*pHistogram +1;//對應偏移量的直方圖陣列元素值累加1
      pHistogram=histogram;//指標重指向直方圖陣列的起始地址
      pHistEqualSourceTmp++;//影象指標指向下一個畫素地址
  }

      //初始化直方圖陣列
    for(i=0;i<256;i++)
        tmp_hist[i] = histogram[i];
    //直方圖均衡
    for(i=1; i<256; i++)
        tmp_hist[i] += tmp_hist[i-1];//計算原始影象的累計直方圖
     //建立對映表
    for(i=0; i<256; i++)
        map[i] = tmp_hist[i]*255/pixelSum;

    //給圖片賦予新值
    pHistEqualSourceTmp=pHistEqualSource;
    for(i = 0 ; i < pixelSum;i++)
    {
        ptr=pHistEqualSourceTmp++;
        *pHistResult=map[*ptr];
        pHistResult++;
    }
    pHistResult = &Pixel_Hist[0];
}
//------------膨脹------------//
void Dilation(const unsigned char *pDilationSource)
{
    printf("come into dilation\n");

    //邊緣不做處理
    for(i=0;i<wSize;i++)
        pDilationResult[i] = pDilationSource[i];
    for(i=(hSize-1)*wSize;i<pixelSum;i++)
        pDilationResult[i] = pDilationSource[i];
    for(i=wSize;i<(hSize-2)*wSize+1;i+=wSize)
        pDilationResult[i] = pDilationSource[i];
    for(i=wSize*2-1;i<(hSize-1)*wSize;i+=wSize)
        pDilationResult[i] = pDilationSource[i];
    for(i = 1;i < hSize - 1;i++)
    {
        for(j = 1;j < wSize - 1;j++)
        {
            flag = 1;
            for(int m = i - 1;m < i + 2;m++)
            {
                for(int n = j - 1; n < j + 2;n++)
                {
                    //自身及領域中若有一個為255
                    //則將該點設為255
                    if((int)pDilationSource[i * wSize + j] == 255|| (int)pDilationSource[m * wSize + n] == 255)
                    {
                        flag = 0;
                        break;
                    }
                }
                if(flag == 0)
                    break;
            }
            if(flag == 0)
                pDilationResult[i * wSize + j] = 255;
            else
                pDilationResult[i * wSize + j] = 0;

        }
    }

}
//------------改進版的膨脹------------//
void ImprovedDilation(const unsigned char *pDilationSource)
{
    //printf("come into dilation\n");

    //邊緣不做處理
    for(i=0;i<wSize;i++)
        pDilationResult[i] = pDilationSource[i];
    for(i=(hSize-1)*wSize;i<pixelSum;i++)
        pDilationResult[i] = pDilationSource[i];
    for(i=wSize;i<(hSize-2)*wSize+1;i+=wSize)
        pDilationResult[i] = pDilationSource[i];
    for(i=wSize*2-1;i<(hSize-1)*wSize;i+=wSize)
        pDilationResult[i] = pDilationSource[i];
    for(i = 1;i < hSize - 1;i++)
    {
        for(j = 1;j < wSize - 1;j++)
        {
            //自身及領域中若有一個為255
            //則將該點設為255
            if((int)pDilationSource[i * wSize + j-1] == 255 || (int)pDilationSource[i * wSize + j] == 255||(int)pDilationSource[i * wSize + j+1] == 255)
                pDilationResult[i * wSize + j] = 255;
            else
                pDilationResult[i * wSize + j] = 0;
        }
    }
    for(j = 1;j < wSize - 1;j++)
    {
        for(i = 1;i < hSize - 1;i++)
        {
            //自身及領域中若有一個為255
            //則將該點設為255
            if((int)pDilationSource[(i-1) * wSize + j] == 255 || (int)pDilationSource[i * wSize + j] == 255||(int)pDilationSource[(i+1) * wSize + j] == 255)
                pDilationResult[i * wSize + j] = 255;
            else
                pDilationResult[i * wSize + j] = 0;
        }
    }
}
//------------------霍夫變換---------------//
int HoughLines(const unsigned char *pHoughLinesSource)
{
    //printf("come into HoughLines\n");

    distance = 0;
    diagonal = (int)sqrt(pow(hSize,2)+pow(wSize,2));

    linesCount = (int**)malloc(theta*sizeof(int*));
    linesY = (int**)malloc(theta*sizeof(int*));
    for(i=0;i<theta;i++)
    {
        linesCount[i] = (int*)malloc(diagonal*sizeof(int));
        linesY[i] = (int*)malloc(diagonal*sizeof(int));
    }

    for(i=0;i<theta;i++)
    {
        for(j=0;j<diagonal;j++)
        {
            linesCount[i][j] = 1;
            linesY[i][j] = 1;
        }
    }

    for(i=0;i<hSize;i++)
    {
        for(j=0;j<wSize;j++)
        {
            if((int)pHoughLinesSource[i*wSize+j]!=0)
            {
                for(m=1;m<theta;m++)
                {
                    distance = (int)(i*cos(PI*m/180)+j*sin(PI*m/180));
                    distance = (int)(distance/2+diagonal/2);//對distance值優化,防止為負
                    linesCount[m][distance] +=1;
                    linesY[m][distance] += i;
                }
            }
        }
    }
    tmpDiatance = linesCount[0][0];
    tmpX = 0;
    tmpY = 0;
    for(i=0;i<theta;i++)
    {
        for(j=0;j<diagonal;j++)
        {
            if(linesCount[i][j]>tmpDiatance)
            {
                tmpDiatance = linesCount[i][j];
                tmpX = i;
                tmpY = j;

            }
        }
    }

    intercept = linesY[tmpX][tmpY]/linesCount[tmpX][tmpY];
    printf("intercept = %d\n",intercept);
    return intercept;
}
//-------------Sobel演算法----------//
void Sobel(const unsigned char *pSobelSource)
{
    //printf("come into Sobel\n");
    //邊緣不做處理
    for(i=0;i<wSize;i++)
        pSobelResult[i] = 0;
    for(i=(hSize-1)*wSize;i<pixelSum;i++)
        pSobelResult[i] = 0;
    for(i=wSize;i<(hSize-2)*wSize+1;i+=wSize)
        pSobelResult[i] = 0;
    for(i=wSize*2-1;i<(hSize-1)*wSize;i+=wSize)
        pSobelResult[i] = 0;

    for(int i=1;i<(hSize-1);i++)
    {
        for(int j=1;j<(wSize-1);j++)
        {
            //通過指標遍歷影象上每一個畫素
            gradX=pSobelSource[(i-1)*wSize+j+1]+pSobelSource[i*wSize+j+1]*2+pSobelSource[(i+1)*wSize+j+1]-pSobelSource[(i-1)*wSize+j-1]-pSobelSource[i*wSize+j-1]*2-pSobelSource[(i+1)*wSize+j-1];
            gradY=pSobelSource[(i+1)*wSize+j-1]+pSobelSource[(i+1)*wSize+j]*2+pSobelSource[(i+1)*wSize+j+1]-pSobelSource[(i-1)*wSize+j-1]-pSobelSource[(i-1)*wSize+j]*2-pSobelSource[(i-1)*wSize+j+1];
            amplitudeTmp = abs(gradX)+abs(gradY);
            if(amplitudeTmp>255)
                amplitudeTmp = 255;
            pSobelResult[i*wSize+j] = amplitudeTmp;
        }
    }
}
//-------------改進版Sobel演算法----------//
void ImprovedSobel(unsigned char* pSobelSource)
{
    //printf("come into ImprovedSobel\n");
    pSobelSourceTmp = pSobelSource;

    //邊緣不做處理
    for(i=0;i<wSize;i++)
        pSobelResult[i] = 0;
    for(i=(hSize-1)*wSize;i<pixelSum;i++)
        pSobelResult[i] = 0;
    for(i=wSize;i<(hSize-2)*wSize+1;i+=wSize)
        pSobelResult[i] = 0;
    for(i=wSize<<1-1;i<(hSize-1)*wSize;i+=wSize)
        pSobelResult[i] = 0;

    for(i=1+wSize;i<(hSize-1)*wSize-1;i++)
    {
        gradX = 0;//水平
        gradY = 0;//垂直

        gradX+=(*(pSobelSourceTmp+i-1-wSize))+(*(pSobelSourceTmp+i-wSize))<<1+(*(pSobelSourceTmp+i+1-wSize))-(*(pSobelSourceTmp+i-1+wSize))-(*(pSobelSourceTmp+i+wSize))<<1-(*(pSobelSourceTmp+i+1+wSize));
        gradY+=(*(pSobelSourceTmp+i-1-wSize))+(*(pSobelSourceTmp+i-1))<<1+(*(pSobelSourceTmp+i-1+wSize))-(*(pSobelSourceTmp+i+1-wSize))-(*(pSobelSourceTmp+i+1))<<1-(*(pSobelSourceTmp+i+1+wSize));
        gradX = abs(gradX);
        gradY = abs(gradY);
        pix = gradY>gradX?gradY:gradX;
        *(pSobelResult+i)= pix>threshold?255:0;
    }
}
//--------------計算高斯核係數-------------//
void Kernel(int size,float sigma)
{
   //計算sigmaX的值
   float sigmaX;
   float sum = 0;
   float gaus[3][3];
   const float PI=4.0*atan(1.0); //圓周率π賦值
   int center=size/2;
   int k =0;
   if(sigma>0)
     sigmaX = sigma;
   else
     sigmaX = ((size-1)*0.5 - 1)*0.3 +0.8;

   for(i=0;i<size;i++)
   {
       for(j=0;j<size;j++)
       {
           gaus[i][j]=(1/(2*PI*sigmaX*sigmaX))*exp(-((i-center)*(i-center)+(j-center)*(j-center))/(2*sigmaX*sigmaX));
           sum+=gaus[i][j];
       }
   }

   for(i=0;i<size;i++)
   {
       for(j=0;j<size;j++)
       {
           gaus[i][j]/=sum;
           CoefArray[k] = gaus[i][j];
           printf("  %f",CoefArray[k]);
           k++;
       }
       printf("\n");
   }
}
//------------計算改進版的高斯核係數---------------//
void KernelSignal(int size,float sigma)
{
   //計算sigmaX的值
   float sigmaX;
   float sum = 0;
   float gaus[3];
   const float PI=4.0*atan(1.0); //圓周率π賦值
   int center=size/2;
   int k =0;
   if(sigma>0)
     sigmaX = sigma;
   else
     sigmaX = ((size-1)*0.5 - 1)*0.3 +0.8;

   for(i=0;i<size;i++)
   {
       gaus[i]=(1/(2*PI*sigmaX*sigmaX))*exp(-((i-center)*(i-center))/(2*sigmaX*sigmaX));
       sum+=gaus[i];
   }

   for(i=0;i<size;i++)
   {
       gaus[i]/=sum;
       CoefArray[k] = gaus[i];
       printf("  %f",CoefArray[k]);
       k++;
       printf("\n");
   }
}