이것은 완벽하게 작동 할 수도 있지만 그렇지 않을 수도 있습니다. AsParallel
을 추가하면 적합하다고 생각되면 병렬화 할 수 있습니다.
여기에도 몇 줄을 복사하여 붙여 넣었으므로 오타 또는 불일치 변수가 있는지 알려주거나 수정 해주세요. 그러나 이것은 그것의 요지입니다. 이유 안에서 꽤 빨리해야합니다.
기본적으로 이것은 이해하기가 약간 어려울 수 있으므로 비트를 "잠그고"해당 포인터를 사용하여 byte[]
에 복사하는 것이 좋습니다. 그러면 효과적으로 RGB (A) 값을 모두 복사하여 실제로 쉽게 액세스 할 수 있습니다. 이것은 픽셀을 잡아내는 데 약간의 시간이 걸리기 때문에, 픽셀을 읽는 데 걸리는 시간은 GetPixel
보다 빠릅니다.
일단 이들을 byte[]
개로 가져 오면 각 픽셀 좌표의 값을 비교하는 것만으로도 충분합니다. 필자는 LINQ를 사용하여 필요한 경우 병렬 처리가 쉽도록 선택했으나 실제로 구현할 것인지 선택하지 않을 수도 있습니다. 네가 필요가 있을지 모르겠다.
나는 당신의 구현이 모든 소스가 하나 인 이미지를 가지고있는 것처럼 들리므로 여기에 몇 가지 가정을하였습니다. 즉, 이미지의 크기와 형식이 같다고 가정합니다. 따라서 실제로 그렇지 않은 경우에는 여기에 몇 가지 추가 코드를 지정하여 해결할 수 있습니다.하지만 여전히 쉽습니다. 실제 구현에서
private byte[] UnlockBits(Bitmap bmp, out int stride)
{
BitmapData bmpData = bmp.LockBits(new Rectangle(Point.Empty, bmp.Size), System.Drawing.Imaging.ImageLockMode.ReadOnly, bmp.PixelFormat);
IntPtr ptr = bmpData.Scan0;
stride = bmpData.Stride;
int bytes = Math.Abs(bmpData.Stride) * bmp.Height;
byte[] ret = new byte[bytes];
System.Runtime.InteropServices.Marshal.Copy(ptr, ret, 0, bytes);
bmp.UnlockBits(bmpData);
return ret;
}
private bool AreArraysEqual(byte[] a, byte[] b, int offset, int length)
{
for (int v = 0; v < length; v++)
{
int c = v + offset;
if (a[c] != b[c])
{
return false;
}
}
return true;
}
private IEnumerable<KeyValuePair<Point, Tuple<Color, Color>>> GetDifferences(Bitmap a, Bitmap b)
{
if (a.PixelFormat != b.PixelFormat)
throw new ArgumentException("Unmatched formats!");
if (a.Size != b.Size)
throw new ArgumentException("Unmatched length!");
int stride;
byte[] rgbValuesA = UnlockBits(a, out stride);
byte[] rgbValuesB = UnlockBits(b, out stride);
if (rgbValuesA.Length != rgbValuesB.Length)
throw new ArgumentException("Unmatched array lengths (unexpected error)!");
int bytesPerPixel = Image.GetPixelFormatSize(a.PixelFormat)/8;
return Enumerable.Range(0, a.Height).SelectMany(y =>
Enumerable.Range(0, a.Width)
.Where(x => !AreArraysEqual(rgbValuesA,
rgbValuesB,
(y * stride) + (x * bytesPerPixel),
bytesPerPixel))
.Select(x =>
{
Point pt = new Point(x, y);
int pixelIndex = (y * stride) + (x * bytesPerPixel);
Color colorA = ReadPixel(rgbValuesA, pixelIndex, bytesPerPixel);
Color colorB = ReadPixel(rgbValuesB, pixelIndex, bytesPerPixel);
return new KeyValuePair<Point, Tuple<Color, Color>>(pt, colorA, colorB);
}
}
private Color ReadPixel(byte[] bytes, int offset, int bytesPerPixel)
{
int argb = BitConverter.ToInt32(pixelBytes, offset);
if (bytesPerPixel == 3) // no alpha
argb |= (255 << 24);
return Color.FromArgb(argb);
}
public IEnumerable<KeyValuePair<Point, Color>> GetNewColors(Bitmap _new, Bitmap old)
{
return GetDifferences(_new, old).Select(c => new KeyValuePair<Point, Color>(c.Key, c.Value.Item1));
}
, 당신은 좀 더 철저하게 내가 가진 것보다 엔디 언 및 픽셀 형식에 대해 생각 할 수도 있지만,이 개념의 증거로 어느 정도 작동합니다, 나는 대부분을 처리 할 것으로 판단 실용적인 사례들.
@TaW가 의견에서 언급했듯이, 변경되지 않은 항목을 모두 블랭킹 (알파를 0으로 설정) 할 수도 있습니다. 또한 픽셀 잠금 해제를 통해 이익을 얻을 수 있습니다. 다시 말하지만, 어떻게하는지 알려주는 튜토리얼이 있습니다. 그러나 이것의 대부분은 동일하게 유지 될 수 있습니다.
허용되는 크기의 가운데 사각형을 가져 와서 해당 영역 내에서 임의의 픽셀을 비교하는 방법은 어떻습니까? – PeteGO
하나의 아이디어는 모든 [10th, 5th, 2nd] 픽셀을 확인하여 시작하고, 변경 사항이 확인되면 확인하는 영역을 수정하는 것입니다. – user1274820
'GetPixel' 또한 매우 느린 방법입니다. 'UnlockBits' 접근법을 시도하십시오. 당신이 그것을 보았다면 많은 튜토리얼이 있으며, 훨씬 더 빠릅니다. –