문제는 특정 색을 무작정 다른 색으로 바꿔 버리니 색이 얼룩덜룩하게 표현되고, 특히나 글씨는 거의 알아 볼수 없을 정도로 뭉개져 버리는 것이다.
그래서 구현한 것이 해당 구역의 색 채도를 기준으로 변환할 색의 색조를 맞추어서 변경했다.
여기서 적용한 것이 HSL to RGB & RGB to HSL.
RGB 는 Red, Green, Blue 색상의 조합으로 색을 표현한 것이란 것은 다 알테고.
HSL 는 Red 색을 기준으로 색조, 채도, 명도를 지정해서 색을 표현한 것이다.
여기서 흐림을 조절하기 위해 명도를 사용한 것이다.
즉, 원래 색의 명도를 알아내서 바꿀 색의 명도를 같에 맞춰 줌으로서 특정 색조가 부드럽게 전환되게 만들수 있다.
[ HSL to RGB & RGB to HSL Class ]
public class RGBHSL { public RGBHSL() { } public class HSL { public double setH { get; set; } public double setS { get; set; } public double setL { get; set; } public double setW { get; set; } public double H { get { return this.setH; } set { setH = value; } } public double S { get { return this.setS; } set { setS = value; } } public double L { get { return this.setL; } set { setL = value; } } public double W { get { return this.setW; } set { setW = value; } } public HSL() { this.setH = 0; this.setS = 0; this.setL = 0; this.setW = 0; } public HSL(double h, double s, double l, double w) { this.setH = h; this.setS = s; this.setL = l; this.setW = w; } public static Color HSL_TO_RGB(HSL hsl) { double r = 0; double g = 0; double b = 0; double temp1, temp2; if (hsl.L == 0) { r = g = b = 0; } else { if (hsl.S == 0) { r = g = b = hsl.L; } else { temp2 = ((hsl.L <= 0.5) ? hsl.L * (1.0 + hsl.S) : hsl.L + hsl.S - (hsl.L * hsl.S)); temp1 = 2.0 * hsl.L - temp2; double[] t3 = new double[] { hsl.H + 1.0 / 3.0, hsl.H, hsl.H - 1.0 / 3.0 }; double[] clr = new double[] { 0, 0, 0 }; for (int i = 0; i < 3; i++) { if (t3[i] < 0) t3[i] += 1.0; if (t3[i] > 1) t3[i] -= 1.0; if (6.0 * t3[i] < 1.0) clr[i] = temp1 + (temp2 - temp1) * t3[i] * 6.0; else if (2.0 * t3[i] < 1.0) clr[i] = temp2; else if (3.0 * t3[i] < 2.0) clr[i] = (temp1 + (temp2 - temp1) * ((2.0 / 3.0) - t3[i]) * 6.0); else clr[i] = temp1; } r = clr[0]; g = clr[1]; b = clr[2]; } } return Color.FromArgb((int)(255 * r), (int)(255 * g), (int)(255 * b)); } public static HSL RGB_TO_HSL(Color c) { HSL hsl = new HSL(); hsl.setH = c.GetHue() / 360.0; hsl.setL = c.GetBrightness(); hsl.setS = c.GetSaturation(); return hsl; } } }
[ 색 변환 ]
private void btnChangColor_Click(object sender, EventArgs e) { Stopwatch sw = new Stopwatch(); sw.Start(); Rectangle rect = new Rectangle(0, 0, img.Width, img.Height); System.Drawing.Imaging.BitmapData bmpData = img.LockBits(rect, System.Drawing.Imaging.ImageLockMode.ReadWrite, img.PixelFormat); // Get the address of the first line. IntPtr ptr = bmpData.Scan0; // Declare an array to hold the bytes of the bitmap. int bytes = Math.Abs(bmpData.Stride) * img.Height; byte[] rgbValues = new byte[bytes]; System.Runtime.InteropServices.Marshal.Copy(ptr, rgbValues, 0, bytes); int numBytes = 0; Color setColor = new Color(); Color getColor = new Color(); Color setColor02 = new Color(); setColor = Color.FromArgb(255, 0, 0); RGBHSL.HSL setColorHSL = new RGBHSL.HSL(); RGBHSL.HSL getColorHSL = new RGBHSL.HSL(); for (int y = 0; y < img.Height; y++) { for (int x = 0; x < img.Width; x++) { numBytes = (y * (img.Width * 4)) + (x * 4); if (rgbValues[numBytes] != 255 && rgbValues[numBytes + 1] != 255 && rgbValues[numBytes + 2] != 255) { getColor = Color.FromArgb((int)rgbValues[numBytes + 2] , (int)rgbValues[numBytes + 1] , (int)rgbValues[numBytes]); setColorHSL = RGBHSL.HSL.RGB_TO_HSL(setColor); getColorHSL = RGBHSL.HSL.RGB_TO_HSL(getColor); if (getColorHSL.setL > 0.6) { setColorHSL.setL = getColorHSL.setL; setColor02 = RGBHSL.HSL.HSL_TO_RGB(setColorHSL); } else { setColor02 = setColor; } rgbValues[numBytes] = setColor02.B; rgbValues[numBytes + 1] = setColor02.G; rgbValues[numBytes + 2] = setColor02.R; } } } // Copy the RGB values back to the bitmap System.Runtime.InteropServices.Marshal.Copy(rgbValues, 0, ptr, bytes); // Unlock the bits. img.UnlockBits(bmpData); pictureBox1.Invalidate(); sw.Stop(); MessageBox.Show(sw.ElapsedMilliseconds.ToString() + "ms"); }
↓
참고로 명도를 적용하지 않고 변환을 했을 경우.
여기서
if (getColorHSL.setL > 0.6) { setColorHSL.setL = getColorHSL.setL; setColor02 = RGBHSL.HSL.HSL_TO_RGB(setColorHSL); } else { setColor02 = setColor; }
부분은 검은색 처리를 위한 부분이다.
모든 색의 명도가 0 일 경우에는 어떤 색도 검은색으로 표현되기 때문에,
만약 이 부분이 없을 경우 아래 처럼 이미지가 변환 된다.