2009-07-23 3 views
1

Windows 이미지에 배치 할 이미지가 여러 개 있습니다. 이미지 자체는 85 x 85입니다. 각 이미지는 이미지의 모든 위치에 위치 할 수있는 다양한 크기의 실린더 객체가있는 흰색 배경을 가지고 있습니다. 예를 들어.NET 그래픽 이미지

:

이미지 1 : 85w의 엑스 85H에서 원통형 상을 갖는다 :
이미지 (2)는 왼쪽 상단 모서리에서 (25, 35) : 85w의 X의 85H는에서 실린더 화상 보유 (28 42) 위 왼쪽 모서리에서

.NET 그래픽 라이브러리로 프로그래밍 방식으로 위치 (25, 35) 또는 (28, 42)를 결정할 수 있는지 궁금합니다.

기본적으로 원통의 위치를 ​​고정 좌표 (예 : 왼쪽 상단 모서리에서 (10, 10))로 재조정합니다.

답변

1

비트 맵 클래스에는 X 및 Y 좌표가 지정된 비트 맵에서 픽셀의 색을 반환하는 GetPixel 메서드가 포함되어 있습니다. 한 가지 기술은 비 - 화이트 픽셀이 존재하는 가장 낮은 X 및 Y 좌표를 결정하기 위해 데이터의 행 및 열을 이동하는 것일 수 있습니다. GetPixel을 호출하는 것이 다소 느리기 때문에 이미지가 작거나 성능이 중요하지 않은 경우이 기술이 적합합니다.

또 다른 방법은 Bitmap 이미지 데이터를 byte []로 가져온 다음 배열에서 바이트를 걷어 흰색 픽셀이 아닌 위치를 결정하는 것입니다. 이 접근법은 주어진 비트 맵 유형 (예 : 32 비트, 24 비트, 1 비트 등)에 대해 바이트가 배치되는 방식에 대한 약간의 지식이 필요합니다.

비트 맵의 ​​바이트를 가져 오려면 비트 맵의 ​​LockBits 메서드를 호출하여 비트 맵의 ​​영역을 잠그고 BitmapData 객체를 가져옵니다. 그런 다음 BitmapData 객체의 Stride 및 Height 속성을 사용하여 비트 맵을 포함하는 데 필요한 바이트 배열의 크기를 결정합니다.

필자는 타원의 위치를 ​​감지하기 위해 만든 몇 개의 테스트 이미지에서 빠르게 작동하는 것으로 보이는 다음 방법을 채우고 테스트했습니다.

private Point DetectLocation(Bitmap original) 
{ 
    Bitmap source = null; 

    // If original bitmap is not already in 32 BPP, ARGB format, then convert 
    if (original.PixelFormat != PixelFormat.Format32bppArgb) 
    { 
     source = new Bitmap(original.Width, original.Height, PixelFormat.Format32bppArgb); 
     source.SetResolution(original.HorizontalResolution, original.VerticalResolution); 
     using (Graphics g = Graphics.FromImage(source)) 
     { 
      g.DrawImageUnscaled(original, 0, 0); 
     } 
    } 
    else 
    { 
     source = original; 
    } 

    // Lock source bitmap in memory 
    BitmapData sourceData = source.LockBits(new Rectangle(0, 0, source.Width, source.Height), ImageLockMode.ReadOnly, PixelFormat.Format32bppArgb); 

    // Copy image data to binary array 
    int imageSize = sourceData.Stride * sourceData.Height; 
    byte[] sourceBuffer = new byte[imageSize]; 
    Marshal.Copy(sourceData.Scan0, sourceBuffer, 0, imageSize); 

    // Unlock source bitmap 
    source.UnlockBits(sourceData); 

    int sourceIndex = 0; 
    int pixelTotal = 0; 
    int height = source.Height; 
    int width = source.Width; 
    int threshold = 255 * 3; 

    int minX = width; 
    int minY = height; 

    // Iterate lines 
    for (int y = 0; y < height; y++) 
    { 
     sourceIndex = y * sourceData.Stride; 

     // Iterate pixels 
     for (int x = 0; x < width; x++) 
     { 
      // Compute pixel brightness (i.e. total of Red, Green, and Blue values) 
      pixelTotal = sourceBuffer[sourceIndex + 1] + sourceBuffer[sourceIndex + 2] + sourceBuffer[sourceIndex + 3]; 
      if (pixelTotal < threshold) 
      { 
       minX = Math.Min(minX, x); 
       minY = Math.Min(minY, y); 
      } 
      sourceIndex += 4; 
     } 
    } 

    return new Point(minX, minY); 
} 
+0

BTW, 안전하지 않은 코드 및/또는 포인터가 신속하고 효율적으로 작동하지 않아도됩니다. –

1

이 실린더가 (모양으로) 얼마나 복잡했는지는 모르겠지만 모든 픽셀을 통과하여 어떤 행과 열이 아닌 첫 번째 흰색이 아닌 픽셀을 찾을 수 있습니다.

+0

AFAIK, AFAIK, AFAIK, AFAIK, 실린더는 아마도 일부 Photoshop 응용 프로그램에서 그래픽에 맞춰 뒤집어 엎었습니다. – coson

+0

어쨌든, 행/열을 검색하고 첫 번째 행과 마지막 행/열을 찾음으로써 왼쪽, 오른쪽, 위, 아래를 찾은 다음 그 사각형을 복사하면 필요한 것을 얻을 수 있습니다. 또한 BitmapData를 가져 와서 안전하지 않은 컨텍스트 (원시 비트 맵 데이터에 대한 조작 포인터를 통해)에서 스캔 할 수 있습니다. 그러면 GetPixel()을 사용하는 것이 훨씬 빠릅니다. –