2012-02-12 3 views
0

지정된 색상으로 찾은 첫 번째 픽셀의 점/좌표 (x, y)를 찾아야합니다. GetPixel() 메서드를 사용했지만 너무 느려서 LockBits를 조사하고있었습니다. 어떻게 이것이 실제로 내 문제를 해결할 수 있는지는 알 수 없다. LockBits를 사용하여 발견 된 픽셀의 점을 반환 할 수 있습니까? 여기 색상 반환 지점으로 픽셀 찾기

내 현재 코드입니다 :

public Point FindPixel(Image Screen, Color ColorToFind) 
{ 
    Bitmap bit = new Bitmap(Screen); 
    BitmapData bmpData = bit.LockBits(new Rectangle(0, 0, bit.Width, bit.Height), 
            ImageLockMode.ReadWrite, 
            PixelFormat.Format32bppPArgb); 
    unsafe 
    { 
     byte* ptrSrc = (byte*)bmpData.Scan0; 
     for (int y = 0; y < bmpData.Height; y++) 
     { 
      for (int x = 0; x < bmpData.Width; x++) 
      { 
       Color c = bit.GetPixel(x, y); 
       if (c == ColorToFind) 
        return new Point(x, y); 
      } 
     } 
    } 
    bit.UnlockBits(bmpData); 
    return new Point(0, 0); 
} 

답변

1

몇 가지 코드 문제가 있습니다 : 당신은 PixelFormat.Format32bppPArgb를 사용하는

  1. - 그들이 경우, 이미지의 픽셀 형식을 사용해야합니다 일치하지 않으면 모든 픽셀이 두 번에 복사됩니다.
  2. 당신은 여전히 ​​GetPixel을 사용하고 있으므로이 모든 번거 로움 때문에 어떤 이점도 얻지 못할 것입니다.

LockBits을 효율적으로 사용하려면 기본적으로 이미지를 잠근 다음 안전하지 않은 포인터를 사용하여 픽셀 값을 가져와야합니다. 코드는 당신이 정말로 LSB에 파란색 존재와 32bpp의 포맷을해야합니다 가정, 다른 픽셀 형식에 대해 조금 다릅니다이 작업을 수행하는 코드는 다음과 같이 수 :

for (int y = 0; y < bmpData.Height; ++y) 
{ 
    byte* ptrSrc = (byte*)(bmpData.Scan0 + y * bmpData.Stride); 
    int* pixelPtr = (int*)ptrSrc; 

    for (int x = 0; x < bmpData.Width; ++x) 
    { 
     Color col = Color.FromArgb(*pixelPtr); 

     if (col == ColorToFind) return new Point(x, y); 

     ++pixelPtr; //Increate ptr by 4 bytes, because it is int 
    } 
} 

몇몇 발언 :

  • 들어 각 라인의 새로운 ptrSrc는 Scan0 + 보폭 값을 사용하여 계산됩니다. 이것은 포인터가 증가하는 경우 Stride != bpp * width 인 경우 실패 할 수 있기 때문입니다.
  • 파란색 픽셀이 LSB로, 알파가 MSB로 표시되었다고 가정합니다. 그 GDI 픽셀 형식이 이상해 졌기 때문에 그렇다고 생각하지 않습니다.) 다른 방법은 있는지 확인하십시오. , FromArgb() 메서드를 사용하기 전에 역 바이트.
  • 픽셀 형식이 24bpp 인 경우 명백한 이유 때문에 int 포인터를 사용하여 1 (4 바이트) 늘릴 수 없기 때문에 조금 더 까다 롭습니다.
+0

정말 고마워요. 정말 잘 됐어요. 지금은 빨리 타오르는군요! :) LockBits로하고 싶은 것을 설명하기 위해 GetPixel()을 사용했습니다. – KLIM8D

2

당신은 GetPixel()을 사용하지 않아도됩니다. 대신이처럼 쓰기 : 라인은 비트 맵에 거꾸로 저장되기 때문에

int IntToFind = ColorToFind.ToArgb(); 
    int height = bmpData.Height; // These properties are slow so read them only once 
    int width = bmpData.Width; 
    unsafe 
    { 
     for (int y = 0; y < height; y++) 
     { 
      int* pline = (int*)bmpData.Scan0 + y * bmpData.Stride/4; 
      for (int x = 0; x < width; x++) 
      { 
       if (pline[x] == IntToFind) 
        return new Point(x, bit.Height - y - 1); 
      } 
     } 
    } 

이상한 찾고 포인트 생성자가 필요합니다. 실패하면 새로운 Point (0, 0)를 반환하지 마십시오. 유효한 픽셀입니다.

+0

이 목적을 위해'Color.ToArgb()'를 사용하지는 않았습니다. 멋지다! – Rotem

+0

답장을 보내 주셔서 감사합니다. 포인터를 올바른 값을 반환 할 수 없습니다. 어쩌면 내 이미지의 형식이나 형식이 잘못되었을 수도 있습니다. 어쨌든 고마워요 :) – KLIM8D

+0

추측하기가 어렵습니다. 알파 값을 조심하십시오. –