private void NormalizeToPalette() { try { using (Bitmap originalImage = new Bitmap(picOriginal.Image)) { // Can't generate the rendered image here in a using statement as the image will be null in future repaints of the picturebox Bitmap renderedImage = new Bitmap(originalImage.Width, originalImage.Height); for (int x = 0; x < originalImage.Width; x++) { for (int y = 0; y < originalImage.Height; y++) { Color color = originalImage.GetPixel(x, y); // Skip transparent if (color.A == 0) { renderedImage.SetPixel(x, y, color); } else { ColorTuple tup = color.ClosestColor(palette); renderedImage.SetPixel(x, y, tup.ColorValue); } } } picRendered.Image = renderedImage; } } catch (Exception ex) { } }
public CustomPanel(int x, int y, ColorTuple tuple) { X = x; Y = y; PaletteItem = tuple; //BackColor = tuple.ColorValue; BorderStyle = BorderStyle.FixedSingle; }
public ColorTuple getRandomColor() { int idx = Random.Range(0, 10); ColorTuple T = new ColorTuple(); T.color = possibleColors[idx]; T.index = idx; return(T); }
public void ChangeColor() { colorIndex = ((colorIndex < colors.Count - 1) ? colorIndex + 1 : 0); selectedColor = colors [colorIndex]; GetComponent <MeshRenderer> ().sharedMaterial.mainTexture = gradientTexture; for (int i = 0; i < gradientTexture.width; i++) { //Debug.Log (i / (float)gradientTexture.width); gradientTexture.SetPixel(i, 0, Color.Lerp(selectedColor.colorL, selectedColor.colorR, i / (float)gradientTexture.width)); } gradientTexture.Apply(); //Camera.main.backgroundColor = selectedColor.colorL; }
/// <summary> /// 将颜色相近的像素连接成连通分量,根据每个联通分量的性质判断是否是文字 /// 默认假设浅色文字周围有深色的边框,否则需要反转 /// </summary> /// <param name="b"></param> /// <param name="reversed">false:浅色文字,深色边框/背景,true:深色文字,浅色边框/背景</param> /// <returns></returns> public static Bitmap Process(Bitmap b, bool reversed) { int width = b.Width; int height = b.Height; float[,,] pixel = new float[width, height, 3]; int[,] selected = new int[width, height]; //把像素值转换成0-1之间的浮点数,存入pixel NormalizeBitmap(b, pixel, reversed); //将颜色相近的像素合并成色块,并去掉和图片边缘相邻的所有色块(假设文字在图片内部) //注:此时还不知道文字是什么颜色的 //将那些最有可能是文字的色块所包含的像素坐标存入textPixels int[,] components = new int[width, height]; List <(int, int)> textPixels = new List <(int, int)>(); List <int> validLevels = new List <int>(); int cur = 1; //先遍历边缘,再遍历中间 for (int x = 0; x < width; x++) { if (components[x, 0] == 0) { VisitComponent(x, 0, cur, components, pixel, textPixels, validLevels, true); } if (components[x, height - 1] == 0) { VisitComponent(x, height - 1, cur, components, pixel, textPixels, validLevels, true); } } for (int y = 1; y < height - 1; y++) { if (components[0, y] == 0) { VisitComponent(0, y, cur, components, pixel, textPixels, validLevels, true); } if (components[width - 1, y] == 0) { VisitComponent(width - 1, y, cur, components, pixel, textPixels, validLevels, true); } } ++cur; for (int x = 1; x < width - 1; x++) { for (int y = 1; y < height - 1; y++) { if (components[x, y] == 0) { VisitComponent(x, y, cur, components, pixel, textPixels, validLevels, false); ++cur; } } } //判断文字宽度的范围 double meanLevel = validLevels.Average(), levelDistSum = 0; foreach (var lv in validLevels) { levelDistSum += (lv - meanLevel) * (lv - meanLevel); } double levelStddev = Math.Sqrt(levelDistSum / Math.Max(1, validLevels.Count)); int minLevel = 2, maxLevel = 3, levelThresh = (int)Math.Round(meanLevel + 2.5 * levelStddev); foreach (var lv in validLevels) { if (lv <= levelThresh) { maxLevel = Math.Max(maxLevel, lv + 2); } } int minSize = 5; //假设上一步找到的像素中大部分都属于文字 //由于第一轮寻找的条件相对苛刻,很难保证找到所有文字像素,所以我们需要第二轮寻找 //找出这些像素颜色的近似(加权)几何中位数,以及标准差 //我们猜测这个几何中位数就是文字的颜色 float stddiv; ColorTuple median = GeometricMedian(textPixels, pixel, out stddiv); float radius = Math.Min(1.1f * stddiv, 0.3f); radius = Math.Max(radius, 0.1f); //把颜色接近几何中位数的所有像素标记为疑似文字像素(标为1),去除其他像素(标为0) //标为1的像素之间互相是联通的 Relabel(pixel, components, median, radius); for (int x = 0; x < width; x++) { for (int y = 0; y < height; y++) { //遍历所有可能是文字的色块 if (components[x, y] == 1) { List <(int, int)> visited = new List <(int, int)>(); bool isBorder = false; List <(int, int)> boundary = ComputeBoundary(median, x, y, 2, pixel, components, visited, out isBorder); //如果当前色块与边界接壤,则舍弃 if (!isBorder) { int level = ComputeLevelWithBoundary(boundary, components[x, y], maxLevel, components); //如果当前色块的宽度/大小符合要求,则记录,否则舍弃 if ((visited.Count >= minSize || level >= minLevel) && level <= maxLevel) { foreach (var t in visited) { selected[t.Item1, t.Item2] = 1; } } } } } } //将记录下来的色块标为白色,其他标为黑色 return(SelectedThreshold(b, selected)); }
//TODO : Add commandline args handling static void Main(string[] args) { /* * 1. Open the palette and create a dictionary of name, color * 2. Open image and iterate over all pixels, across columns, then rows * 3. For each pixel, resolve into nearest color from palette and add to the order sheet * NOTE : Transparent pixels don't enter into the count */ string srcImage = "test.png"; string srcPalette = "colours.csv"; string outImage = "paletteAdjusted.png"; Dictionary <string, Color> palette = PaletteProcessor.CreatePalette(srcPalette); Dictionary <string, int> orderSheet = new Dictionary <string, int>(); using (Bitmap src = new Bitmap(srcImage)) { using (Bitmap tar = new Bitmap(src.Width, src.Height)) { for (int x = 0; x < src.Width; x++) { for (int y = 0; y < src.Height; y++) { Color color = src.GetPixel(x, y); // Skip transparent if (color.A == 0) { tar.SetPixel(x, y, color); } else { ColorTuple tup = color.ClosestColor(palette); if (!orderSheet.ContainsKey(tup.Name)) { orderSheet.Add(tup.Name, 1); } else { orderSheet[tup.Name]++; } tar.SetPixel(x, y, tup.ColorValue); } } } //Dump the ordersheet StringBuilder sb = new StringBuilder(); foreach (string name in orderSheet.Keys) { sb.AppendFormat("{0}: {1}\r\n", name, orderSheet[name]); } File.WriteAllText("OrderSheet.txt", sb.ToString()); tar.Save(outImage, src.RawFormat); } } }