티스토리 뷰

C#

[C#] 픽셀서치 PixelSearch 2

PRG 2017.09.16 21:44

원래 PixelSearch 주소 : http://jogamja.tistory.com/104

PixelSearch를 좀더 빠르게 할수는 없을까?

GetPixel 보다 더 빠른 방법이없을까 ?

BitBlt 로 캡쳐한 화면의 데이터에 바로 접근하는 방법이 있지않을까 ?

 

그 해결의 실마리는 gdi+ LockBits 이다.

C# 에서는 Bitmap.LockBits 로 사용할수있으며  LockBits는 RGB bit 들을 묶어(Lock)놓는것이다.

다시말해서, 비트맵에 내가 지정한 직사각형 부분을 잠궈놓고 내가 마음대로 사용할수 있게해주는 함수이다.

LockBits에 대한 내용은 https://msdn.microsoft.com/ko-kr/library/5ey6h79d(v=vs.110).aspx 여기에 더 자세히 나와있다.

또, 이것을 활용하기위한 사전지식은

https://m.blog.naver.com/PostView.nhn?blogId=xneokr&logNo=60118025489&proxyReferer=http%3A%2F%2Fwww.google.co.kr%2Furl%3Fsa%3Dt%26rct%3Dj%26q%3D%26esrc%3Ds%26source%3Dweb%26cd%3D4%26ved%3D0ahUKEwi3ubiQ16nWAhVGfbwKHYxRD8EQFgg7MAM%26url%3Dhttp%253A%252F%252Fm.blog.naver.com%252Fxneokr%252F60118025489%26usg%3DAFQjCNFfG4H-4fnUqRRt62fOCxca-2o0Hw

이 블로그에서 보자.  ( 잘 설명되어있다고 생각함)

 

간략히 설명하면,

Scan0  : 비트맵 배열의 첫주소. Stride : 비트맵의 가로길이 + 여백   ( 스캔너비)  Width : 가로길이 Height : 높이

Format24bppRgb : RGB에 관한 내용만있음. 각각 8bit씩 총 3byte  Format32bppRgb : RGB + 투명도를 담당하는 알파채널 8bit. 각각 8bit씩 총 4byte.

이정도만 알아도 PixelSearch의 주요부분을 바꾸기에 충분할것이다.

 

함수의 순서는 다음과같다.

1. System.Runtime.InteropServices.Marshal.Copy 를 이용하여 Scan0 주소부터 시작해서 바이트배열 rgbValue에 집어넣는다.

2. Width와 Height에 관한 반복문 내에서 원하는 픽셀있다면 return한다.

3. 반복문이 끝났다면 return 한다.

 

// CaptureScreen() 은 화면 촬영함수.  맨위에 PixelSearch 원본 주소에서 BitBlt부분 이용해서 만들어야됨.

// unsafe 키워드를 넣고 작성할거면 포인터로 해결하는게 좋다.  24bppRgb이므로 Scan0의 주소를 포인터 ptr 에 저장해서 ptr을 3씩 증가시키며 픽셀을 비교하는게 아래 소스보다 더 편하다.

//

public int[] PixelSearch(int x1,int y1,int x2,int y2 , Color c)

{

int result = [-1,0,0]; // result[0] == -1 -> false ,  result[1] ,result[2] = x , y

if ( x1 >= x2 || y1 >= y2)

return result;

Bitmap scr = CaptureScreen(); // 화면촬영

if ( x2 > scr.Width || y2 > scr.Height)

return result;

Rectangle rect = new Rectangle(x1 ,y1 ,x2-x1 ,y2-y1);

BitmapData scrdata =  scr.LockBits(rect,System.Drawing.Imaging.ImageLockMode.ReadOnly,PixelFormat.Format24bppRgb);

int stride = scrdata.Stride;

int Height = y2 - y1;

int Width = x2 - x1;

int size = stride * Height;

byte[] rgbValue = new byte[size];

byte[] comData = { c.B ,c.G , c.R} ;   // rgbValue에 BGR 순으로 저장되기때문에 이 순서대로 저장.

System.Runtime.InteropServices.Marshal.Copy(scrdata.Scan0, rgbValue, 0, size); // rgbValue에 복사.

scr.UnlockBits(scrdata);

// 비교 방향은 x방향부터 먼저확인.

// x,y 의 rgb픽셀의 시작은 stride * y + j * 3 에 있다.   픽셀이 3byte씩 들어있고 stride가 열의 갯수이기 때문이다.

for(int i = 0 ; i < Height ; i++)

{

for(int j = 0 ; j< Width ; j++)

{

if ( rgbValue[stride*i + j*3] == comData[0] && rgbValue[stride*i +j*3+ 1] == comData[1] && rgbValue[stride*i + j*3 + 2] == comData)

{

result[0] = 1;

result[1] = j;

result[2] = i;

return result;

}

}

}

return result

}

 

오차부분을 추가하고싶으면 함수내부에 오차부분 구간 설정해주는 코드만 작성해주면 된다.

댓글
댓글쓰기 폼