원래 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 여기에 더 자세히 나와있다.
또, 이것을 활용하기위한 사전지식은
이 블로그에서 보자. ( 잘 설명되어있다고 생각함)
간략히 설명하면,
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
}
오차부분을 추가하고싶으면 함수내부에 오차부분 구간 설정해주는 코드만 작성해주면 된다.
'C#' 카테고리의 다른 글
[C#] HSV에서 Hue 의 거리 (0) | 2018.07.09 |
---|---|
[C#] 이미지를 오로지 R , G , B 만으로 표현하기 (색 분류) (0) | 2017.12.28 |
[C#] 픽셀서치 PixelSearch (4) | 2017.08.25 |
[C#] Xamarin with CocosSharp 공튀기기 (0) | 2017.03.04 |
[C#] 자마린 무료화 (0) | 2017.03.01 |
댓글