2012-03-08 2 views
1

색상을 기반으로 개체를 추적하고 EmguCV 라이브러리를 사용하여 내 색상 이미지를 이진 흑백 이미지로 임계 값을 설정하려고했습니다. 임계 값 자체는 320x240 이미지에서 50ms로 매우 빨랐습니다. RG Chromaticity 색 공간을 사용하고 있으므로 반드시 계산해야합니다.C에서 내 색상 thresholding 속도를내는 방법

이제는 포인터를 사용하여 속도를 높이려고했지만 결과는 emguCV (이미지 당 약 50ms)로 수행 한 것과 매우 유사합니다.

나를 도울 수있는 전문가가 있다면, 내가 뭘 잘못하고 있는지 물어보고 싶습니다. 다음은 내 색상 임계 값 구현의 짧은 코드 스 니펫입니다. 이 코드는 http://www.bobpowell.net/onebit.htm을 기반으로합니다.

public static Bitmap ThresholdRGChroma(Bitmap original, double angleMin, 
      double angleMax, double satMin, double satMax) 
{ 
    Bitmap bimg = new Bitmap(original.Width, original.Height, PixelFormat.Format1bppIndexed); 

    BitmapData imgData = original.LockBits(new Rectangle(0, 0, original.Width, original.Height), ImageLockMode.ReadOnly, original.PixelFormat); 
    BitmapData bimgData = bimg.LockBits(new Rectangle(0, 0, bimg.Width, bimg.Height), ImageLockMode.ReadWrite, bimg.PixelFormat); 

    int pixelSize = 3; 

    double r, g, angle, sat; 

    unsafe 
    { 
     byte* R, G, B; 
     byte* row; 
     int RGBSum; 

     for (int y = original.Height - 1; y >= 0; y--) 
     { 
      row = (byte*)imgData.Scan0 + (y * imgData.Stride); 

      for (int x = original.Width - 1; x >= 0; x--) 
      { 
       // get rgb values 
       B = &row[x * pixelSize]; 
       G = &row[x * pixelSize + 1]; 
       R = &row[x * pixelSize + 2]; 

       RGBSum = *R + *G + *B; 

       if (RGBSum == 0) 
       { 
        SetIndexedPixel(x, y, bimgData, false); 
        continue; 
       } 

       //calculate r ang g for rg chroma color space 
       r = (double)*R/RGBSum; 
       g = (double)*G/RGBSum; 

       //and angle and saturation 
       angle = GetAngleRad(r, g) * (180.0/Math.PI); 
       sat = Math.Sqrt(Math.Pow(g, 2) + Math.Pow(r, 2)); 

       //conditions to set pixel black or white 
       if ((angle >= angleMin && angle <= angleMax) && (sat >= satMin && sat <= satMax)) 
        SetIndexedPixel(x, y, bimgData, true); 
       else 
        SetIndexedPixel(x, y, bimgData, false); 
      } 

     } 
    } 

    bimg.UnlockBits(bimgData); 
    original.UnlockBits(imgData); 

    return bimg; 
} 

private unsafe static void SetIndexedPixel(int x, int y, BitmapData bmd, bool pixel) 
{ 
    int index = y * bmd.Stride + (x >> 3); 
    byte* p = (byte*)bmd.Scan0.ToPointer(); 
    byte mask = (byte)(0x80 >> (x & 0x7)); 

    if (pixel) 
     p[index] |= mask; 
    else 
     p[index] &= (byte)(mask^0xff); 
} 

private static double GetAngleRad(double x, double y) 
{ 
    if (x - _rgChromaOriginX == 0) 
     return 0.0; 
    double angle = Math.Atan((y - _rgChromaOriginY)/(x - _rgChromaOriginX)); // 10ms 

    if (x < _rgChromaOriginX && y > _rgChromaOriginY) 
     angle = angle + Math.PI; 
    else if (x < _rgChromaOriginX && y < _rgChromaOriginY) 
     angle = angle + Math.PI; 
    else if (x > _rgChromaOriginX && y < _rgChromaOriginY) 
     angle = angle + 2 * Math.PI; 

    return angle; 
} 

답변

1

각 픽셀에 대해 많은 불필요한 계산을 수행하고 정확한 값만 계산하여 일부 한계 내에 있는지 확인합니다. 한계에 대한 일부 조정을 사전 계산하여 비교를 단순화 할 수 있습니다.

가장 쉬운 대체는 채도에 대한 것입니다. 대신에 한계를 제곱함으로써 피할 수있는 제곱근을하고 있습니다.

double satMin2 = satMin*satMin; 
double satMax2 = satMax*satMax; 
// ... 
sat2 = g*g + r*r; 

//conditions to set pixel black or white 
if ((angle >= angleMin && angle <= angleMax) && (sat2 >= satMin2 && sat <= satMax2)) 

각도로 비슷한 트릭을 사용할 수 있습니다. Math.Atan을 사용하여 각도를 계산하는 대신 r 및 g 범위에서 그 한계가 동일한 지 파악하십시오.

+0

고맙습니다. 채도와 범위를 수정하는 것만으로 50에서 30까지 약 20ms의 thresholding 속도가 향상됩니다. 나는이 멋진 [paper] (http://www.lucs.lu.se/LUCS/M012/Minor12.pdf) RG- 색도에 관해서는 Atan을 제거함으로써 당신이 말했던 것과 똑같이 속도를 향상시키는 법을 보여줍니다. 내 컴퓨터에서 임계 값 인 320x240 이미지를 18ms 이내에 게시합니다. – LadislavM

0

더 빠를 지 모르겠습니다. 그러나 here 나는 팁을 썼다. 비트 맵을 매우 빠르게 다루는 법.

+0

답변 주셔서 감사합니다.하지만 이미 비슷한 접근 방식을 사용하고 있습니다. 너의 복잡하지만. – LadislavM

0

완전성을 위해 RG Chromaticity 색 공간에서 thresholding 이미지의 수정 된 버전이 내 질문에서 버전보다 2 배 이상 빠릅니다.

 
public static Bitmap ThresholdRGChroma(Bitmap original, Rectangle roi, double angle, 
      double width, double satMin, double satMax) 
     { 
      Bitmap bimg = new Bitmap(original.Width, original.Height, PixelFormat.Format1bppIndexed);

BitmapData imgData = original.LockBits(new Rectangle(0, 0, original.Width, original.Height), ImageLockMode.ReadOnly, original.PixelFormat); BitmapData bimgData = bimg.LockBits(new Rectangle(0, 0, bimg.Width, bimg.Height), ImageLockMode.ReadWrite, bimg.PixelFormat); int pixelSize = 3; double r, g, sat, m; double satMin2 = satMin * satMin; double satMax2 = satMax * satMax; double cr = Math.Sin((2 * Math.PI * angle)/360.0); double cg = Math.Cos((2 * Math.PI * angle)/360.0); // Instead of (Math.Cos(2 * width/180.0) + 1)/2.0 I'm using pre-calculated <1; 0> values. double w2 = -width; unsafe { byte* R, G, B; byte* row; int RGBSum; for (int y = original.Height - 1; y >= 0; y--) { row = (byte*)imgData.Scan0 + (y * imgData.Stride); for (int x = original.Width - 1; x >= 0; x--) { B = &row[x * pixelSize]; G = &row[x * pixelSize + 1]; R = &row[x * pixelSize + 2]; RGBSum = *R + *G + *B; if (RGBSum == 0) { SetIndexedPixel(x, y, bimgData, false); continue; } r = (double)*R/RGBSum - _rgChromaOriginX; g = (double)*G/RGBSum - _rgChromaOriginY; m = cr * r + cg * g; sat = r * r + g * g; if (m > 0 && m * m > w2 * w2 * sat && sat >= satMin2 && sat <= satMax2) SetIndexedPixel(x, y, bimgData, true); else SetIndexedPixel(x, y, bimgData, false); } } } bimg.UnlockBits(bimgData); original.UnlockBits(imgData); return bimg; }
관련 문제