using System;
using System.Collections.Generic;
using System.Drawing;
namespace NeuralNetwork.PictureWork
{
public static class PictureWork
{
/// <summary>
/// Заменяет прозрачные области белым цветом.
/// </summary>
/// <param name="src">Исходное изображение</param>
/// <returns></returns>
public static Bitmap RemoveTransparency(Bitmap src)
{
Bitmap target = new Bitmap(src.Size.Width, src.Size.Height);
Graphics g = Graphics.FromImage(target);
g.Clear(Color.White);
g.CompositingMode = System.Drawing.Drawing2D.CompositingMode.SourceOver;
g.DrawImage(src, 0, 0);
return target;
}
/// <summary>
/// Выполняет поиск прямоугольных областей на рисунке, содержащих объекты.
/// </summary>
/// <param name="m">Матрица яркости пикселей значениями от 0 до 1.</param>
/// <returns>Возвращает массив прямоугольных областей, где были найдены объекты.</returns>
public static Rectangle[] FindObjects(float[][] m)
{
int y1 = -1, y2 = -1;
for (int i = 0; i < m.Length && y1 == -1; i++)
for (int j = 0; j < m[i].Length; j++)
if ((int)Math.Round(m[i][j]) == 1)
{
y1 = i;
break;
}
for (int i = m.Length - 1; i > y1 && y2 == -1; i--)
for (int j = 0; j < m[i].Length; j++)
if ((int)Math.Round(m[i][j]) == 1)
{
y2 = i;
break;
}
int xEnd = 0;
List<Rectangle> digits = new List<Rectangle>();
Rectangle current;
while (true)
{
current = FindObject(m, y1, y2, xEnd, ref xEnd);
if (current != Rectangle.Empty)
digits.Add(current);
else
break;
}
return digits.ToArray();
}
/// <summary>
/// Выполняет поиск объекта среди всей матрицы яркости в заданных границах
/// </summary>
/// <param name="m">Матрица яркости пикселей значениями от 0 до 1.</param>
/// <param name="y1">Верхняя граница поиска по высоте.</param>
/// <param name="y2">Нижняя граница поиска по высоте.</param>
/// <param name="xStart">Крайняя левая граница поиска по ширине.</param>
/// <param name="xEnd">Крайняя правая граница поиска по ширине.</param>
/// <returns>Возвращает прямоугольную область - границы найденного изображения.</returns>
public static Rectangle FindObject(float[][] m, int y1, int y2, int xStart, ref int xEnd)
{
int x1 = -1, x2 = -1;
for (int j = xStart; j < m[0].Length && x1 == -1; j++)
for (int i = y1; i < y2; i++)
if ((int)Math.Round(m[i][j]) == 1)
{
x1 = j;
break;
}
if (x1 != -1)
{
for (int j = x1 + 1, k; j < m[0].Length; j++)
{
k = 0;
for (int i = y1; i < y2; i++)
k += (int)Math.Round(m[i][j]);
if (k == 0)
{
x2 = j - 1;
break;
}
}
if (x2 == -1)
x2 = m.Length - 1;
xEnd = x2 + 1;
return new Rectangle(x1, y1, x2 - x1 + 1, y2 - y1 + 1);
}
return Rectangle.Empty;
}
/// <summary>
/// Выполняет конвертацию изображения в матрицу яркости.
/// </summary>
/// <param name="bmp">Исходное изображение.</param>
/// <returns>Возвращает матрицу яркости пикселя значениями от 0 до 1.</returns>
public unsafe static float[][] BitmapToFloatMatrixRgbQ(Bitmap bmp)
{
int width = bmp.Width,
height = bmp.Height;
System.Drawing.Imaging.BitmapData bd = bmp.LockBits(
new Rectangle(0, 0, width, height),
System.Drawing.Imaging.ImageLockMode.ReadOnly,
System.Drawing.Imaging.PixelFormat.Format32bppRgb);
float[][] matrix = new float[height][];
try
{
unsafe
{
for (int h = 0; h < height; ++h)
{
matrix[h] = new float[width];
byte* row = (byte*)bd.Scan0 + (h * bd.Stride);
int columnOffset = 0;
for (int w = 0; w < width; ++w)
{
byte B = row[columnOffset];
byte G = row[columnOffset + 1];
byte R = row[columnOffset + 2];
columnOffset += 4;
matrix[h][w] = (255f - (float)Math.Round((R + G + B) / 3f)) / 256f;
}
}
}
}
finally
{
bmp.UnlockBits(bd);
}
return matrix;
}
/// <summary>
/// Выполняет конвертацию изображения в матрицу яркости.
/// </summary>
/// <param name="bmp">Исходное изображение.</param>
/// <returns>Возвращает матрицу яркости пикселя значениями от 0 до 1.</returns>
public unsafe static float[] BitmapToFloatArrayRgbQ(Bitmap bmp)
{
int width = bmp.Width,
height = bmp.Height;
System.Drawing.Imaging.BitmapData bd = bmp.LockBits(
new Rectangle(0, 0, width, height),
System.Drawing.Imaging.ImageLockMode.ReadOnly,
System.Drawing.Imaging.PixelFormat.Format32bppRgb);
float[] _array = new float[height * width];
try
{
unsafe
{
for (int h = 0; h < height; ++h)
{
byte* row = (byte*)bd.Scan0 + (h * bd.Stride);
int columnOffset = 0;
for (int w = 0; w < width; ++w)
{
byte B = row[columnOffset];
byte G = row[columnOffset + 1];
byte R = row[columnOffset + 2];
columnOffset += 4;
_array[h * height + w] = (255f - (float)Math.Round((R + G + B) / 3f)) / 256f;
}
}
}
}
finally
{
bmp.UnlockBits(bd);
}
return _array;
}
/// <summary>
/// Выполняет фильтрацию медианным алгоритмом.
/// Для каждого пикселя смотрятся вокруг 8 штук для каждого канала.
/// Выполняется сортировка и выборка среднего медианного значения.
/// </summary>
/// <remarks>
/// Т.к. рассматривается всё изображение кроме окантовки в 1 пиксель по периметру.
/// то окантовка остается белой. Критично - исправить заполнением из исходного изображения.
/// </remarks>
/// <param name="bmp"></param>
/// <returns></returns>
public unsafe static Bitmap MedianFilter(Bitmap bmp)
{
int width = bmp.Width,
height = bmp.Height;
System.Drawing.Imaging.BitmapData bdRead = bmp.LockBits(
new Rectangle(0, 0, width, height),
System.Drawing.Imaging.ImageLockMode.ReadOnly,
System.Drawing.Imaging.PixelFormat.Format32bppRgb);
Bitmap bitmap = new Bitmap(width, height);
System.Drawing.Imaging.BitmapData bdWrite = bitmap.LockBits(
new Rectangle(0, 0, width, height),
System.Drawing.Imaging.ImageLockMode.WriteOnly,
System.Drawing.Imaging.PixelFormat.Format32bppRgb);
Dictionary<string, int[]> RGB_Array = new Dictionary<string, int[]>
{
{ "R", new int[9] },
{ "G", new int[9] },
{ "B", new int[9] },
};
try
{
unsafe
{
for (int h = 1; h < height - 1; ++h)
{
byte* rowRead_Top = (byte*)bdRead.Scan0 + ((h - 1) * bdRead.Stride);
byte* rowRead_Mid = (byte*)bdRead.Scan0 + (h * bdRead.Stride);
byte* rowRead_Bot = (byte*)bdRead.Scan0 + ((h + 1) * bdRead.Stride);
byte* rowWrite = (byte*)bdWrite.Scan0 + (h * bdWrite.Stride);
int columnOffset = 4;
for (int w = 1; w < width - 1; ++w)
{
foreach (var key in RGB_Array.Keys)
{
int colorOffset = -1;
switch (key)
{
case "R": colorOffset = 2; break;
case "G": colorOffset = 1; break;
case "B": colorOffset = 0; break;
default: throw new Exception();
}
// Линия выше
RGB_Array[key][0] = rowRead_Top[columnOffset + colorOffset - 4]; // Левее
RGB_Array[key][1] = rowRead_Top[columnOffset + colorOffset]; // Центр
RGB_Array[key][2] = rowRead_Top[columnOffset + colorOffset + 4]; // Правее
// Линия текущая
RGB_Array[key][3] = rowRead_Mid[columnOffset + colorOffset - 4]; // Левее
RGB_Array[key][4] = rowRead_Mid[columnOffset + colorOffset]; // Центр
RGB_Array[key][5] = rowRead_Mid[columnOffset + colorOffset + 4]; // Правее
// Линия ниже
RGB_Array[key][6] = rowRead_Bot[columnOffset + colorOffset - 4]; // Левее
RGB_Array[key][7] = rowRead_Bot[columnOffset + colorOffset]; // Центр
RGB_Array[key][8] = rowRead_Bot[columnOffset + colorOffset + 4]; // Правее
}
foreach (var array in RGB_Array.Values)
Array.Sort(array);
/*B*/
rowWrite[columnOffset] = (byte)RGB_Array["B"][4];
/*G*/
rowWrite[columnOffset + 1] = (byte)RGB_Array["G"][4];
/*R*/
rowWrite[columnOffset + 2] = (byte)RGB_Array["R"][4];
//end
columnOffset += 4;
}
}
}
}
finally
{
bmp.UnlockBits(bdRead);
bitmap.UnlockBits(bdWrite);
}
return bitmap;
}
public static Bitmap InsertBitmap(Bitmap src, int targetWidth, int targetHeight)
{
Bitmap target = new Bitmap(targetWidth, targetHeight);
Graphics g = Graphics.FromImage(target);
g.Clear(Color.White);
g.CompositingMode = System.Drawing.Drawing2D.CompositingMode.SourceOver;
g.DrawImage(src, 4, 4);
return target;
}
}
}