此代碼與我使用的代碼類似。 當然,在這種情況下,不安全的代碼是唯一的出路。 將內存中的像素編組在內存周圍並不是必需的,而且您必須爲此進行兩次比較!
但是,比較像素應視爲比較兩個數字。 對於顏色的紅色,綠色和藍色成分中的每一個,以及當然經常被忽略的Alpha,像素都是3個字節,您可能想要將值作爲UInt32進行比較。這可以比較一個數字(一個像素)與另一個數字的好處,如果它們相同,那麼你繼續前進。
爲了這個工作,你不需要一個字節*,而是一個UInt32 *。 其次,上面的代碼沒有考慮我能看到的Stride,這是圖像的每條水平線可能實際使用的字節數不同於像素本身總和的地方。正如你可能處理24位(rgb)和alpha(a)這意味着像素應該已經排隊,因此,上面的代碼應該工作。然而,不能保證100%的時間。
這可能聽起來像我很挑剔,但我猜測性能對你來說意義重大 - 而且來自遊戲背景,對我來說也是如此。
(從上面的鏈接採取第1部分,由於卡爾 - 約翰·舍格倫)
BitmapData bData = b.LockBits(new Rectangle(0, 0, _image.Width, _image.Height), ImageLockMode.ReadWrite, b.PixelFormat);
當你點擊這條線,你真的要小心 - 你與鎖定的PixelFormat應該匹配一個你的源圖像的PixelFormat。否則,事情可能不會像你期望的那樣行事。
來自LockBits,您將獲得需要深入挖掘的BitmapData。
byte* scan0 = (byte*)bData.Scan0.ToPointer();
這是我指的是行 - 我會想辦法讓這個UInt32的*所以你不讀一氣呵成每指令一個字節,但4,作爲一個UInt32的。
我會以一個數組的形式訪問這個內存 - 我計算一維數組的偏移量,通過識別步幅是相當於一個Y像素,然後乘以Y.然而,你會在這一點上我陷入了同樣的陷阱!
int stride = bData.Stride/4; // the width is expressed in bytes, yet we need it as UInt32's. As there's 4 bytes per UInt32, this makes sense of the divide by 4.
所以讀出象素可以這樣做:
int x = 123;
int y = 321;
UInt32 pixelColour = scan0[(y * stride) + x];
最後的話,不要忘了,當你完成解鎖你的位圖。一個容易忘記的人。 此外,如果您希望將更改後的像素保存到另一個位圖,則需要以相同的方式寫入像素。我認爲我使用指針作爲數組讀取像素的示例應該很明顯,那麼如何執行相同的操作來寫入像素。
另一個想法 - 我希望你沒有試圖比較Jpeg或其他有損壓縮圖像 - 因爲這些變化可能是非常不可預測的,並且不是你想象的那樣。相反,您需要使用無損圖像格式,如BMP和PNG。
希望這可以幫助別人。
謝謝,你的問題幫了我很多。 – smoothumut 2017-11-29 07:22:55