天天看點

使用C#實作對圖檔内某種顔色的替換

使用C#實作對圖檔内某種顔色的替換

背景:

寫這個程式的起因是前段時間接了個私活,要求用winform做一個給圖檔批量打水印的程式,大概如下這種:

使用C#實作對圖檔内某種顔色的替換

寫完後和另一個朋友聊天時聊到這方面,他問我能畫圖那能不能對圖檔中顔色做替換,比如給證件照換個背景色什麼的,後面我也就抱着試試看的心态做了一下.話不多說,程式如下.

先看看demo的樣子:

使用C#實作對圖檔内某種顔色的替換

很簡單的一個demo,主要實作的功能就是載入圖檔,選擇要替換的顔色(預設查找的是左上角坐标原點的顔色,要替換别的顔色隻需要用滑鼠在那部分單機并點選查找背景色),選擇替換色,替換顔色和儲存的功能.

效果圖:

圖檔處理

使用C#實作對圖檔内某種顔色的替換

(原圖)                   (處理後1)                 (處理後2)

證件照換背景色

使用C#實作對圖檔内某種顔色的替換

(原圖)                            (處理後1)

程式很簡單,大體結構如下: 

使用C#實作對圖檔内某種顔色的替換
使用C#實作對圖檔内某種顔色的替換

核心代碼如下:

/// <summary>
指定顔色替換成另一種顔色
        /// </summary>
原圖</param>
圖寬</param>
圖高</param>
要被替換顔色的RGB的R</param>
要被替換顔色的RGB的G</param>
要被替換顔色的RGB的B</param>
替換色的RGB的R</param>
替換色的RGB的G</param>
替換色的RGB的B</param>
處理後的結果圖像</returns>
        public Bitmap ReplaceColor(Bitmap img, int w, int h, int R, int G, int B, int r, int g, int b)
        {
            Bitmap bt = new Bitmap(ConvertTo32bpp(img));
            Rectangle rect = new Rectangle(0, 0, w, h);
            BitmapData bmpdata = bt.LockBits(rect, ImageLockMode.ReadWrite, bt.PixelFormat);
            IntPtr ptr = bmpdata.Scan0;
            int bytes = Math.Abs(bmpdata.Stride) * bt.Height;
            byte[] rgbValues = new byte[bytes];
            System.Runtime.InteropServices.Marshal.Copy(ptr, rgbValues, 0, bytes);
            int len = rgbValues.Length;
            byte a = (byte)int.Parse(tbTolerance.Text);
            byte R1 = (byte)R;
            byte G1 = (byte)G;
            byte B1 = (byte)B;
            byte r1 = (byte)r;
            byte g1 = (byte)g;
            byte b1 = (byte)b;
            for (int i = 0; i < len; i += 4)
            {      

是用4個位元組表示一個像素,第一個位元組表示RGB的B值,第一個表示為G值,第三個表示為R值,第四個表示為Alpha值

if (Math.Abs(rgbValues[i] - B1) < a && Math.Abs(rgbValues[i + 1] - G1) < a && Math.Abs(rgbValues[i + 2] - R1) < a)
                {
                    rgbValues[i] = b1;
                    rgbValues[i + 1] = g1;
                    rgbValues[i + 2] = r1;
                }
            }
            System.Runtime.InteropServices.Marshal.Copy(rgbValues, 0, ptr, bytes);
            bt.UnlockBits(bmpdata);
            return bt;
        }      

代碼說明:

通過LockBits方法來鎖定系統記憶體中現有的bitmap位圖,使其可以用程式設計的方式進行更改.然後通過用bitmapdata的Scan0屬性來找到位圖第一個像素資料的位置,進而通過bitmapdata的Stride屬性來得到位圖的掃描寬度(和圖檔的width屬性不一樣,Stride是記憶體中實際位圖每行的寬度,存在一個補齊為4的倍數).然後通過寬度和高度的乘積得到位圖在記憶體中占有的位元組(byte)數組大小,進而用Marshal.Copy方法從記憶體中得到這些位圖的像素資料,然後采用for循環去周遊每一個像素(4位元組,順序是bgrAlpha)上的顔色數值和要替換的顔色數值的差的絕對值是否在設定的容差範圍内,如果在就用替換的顔色數值去覆寫原有顔色數值.

程式位址:​

​​https://github.com/JingChao94/ImgDemo​​

參考資料:​

​​https://docs.microsoft.com/zh-cn/dotnet/api/system.drawing.imaging.bitmapdata?view=dotnet-plat-ext-5.0​​

​https://docs.microsoft.com/zh-cn/dotnet/api/system.drawing.bitmap?view=dotnet-plat-ext-5.0​​

作者介紹​

木石:菜鳥軟體工程師.會一點cs和bs程式開發,常用C#,偶爾也改改 python腳本寫寫js之類的,目前在一家自動化公司任職,才開始接觸視覺檢測以及伺服電機梯形圖之類的,希望可以保持進步,持續成長下去.