J
The first thing to achieve the purpose you seek is to increase the contrast of the original image so that the almost white is white. To do this we build the following function:private Bitmap AplicaFiltroContrasteBrillo(Image p_ImgSource, float p_Contraste, float p_Brillo)
{
float brilloAjustado = p_Brillo - 1.0f;
// Creamos una matriz para aplicar contraste y brillo
// a una imagen dada.
float[][] matrizContraste = {
new float[] {p_Contraste, 0, 0, 0, 0}, // aplica a RED
new float[] {0, p_Contraste, 0, 0, 0}, // aplica a GREEN
new float[] {0, 0, p_Contraste, 0, 0}, // aplica a BLUE
new float[] {0, 0, 0, 1.0f, 0}, // canal alpha
new float[] {brilloAjustado, brilloAjustado, brilloAjustado, 0, 1}};
// Creamos los atributos en función de nuestra matriz
// para aplicar a la imagen
ColorMatrix cmx = new ColorMatrix(matrizContraste);
ImageAttributes imgAttr = new ImageAttributes();
imgAttr.SetColorMatrix(cmx);
// Trasladamos la imagen a un bitmap ya con el efecto de contraste
// y brillo aplicado para poder trabajar sobre eso
Bitmap bmpCanvas = new Bitmap(p_ImgSource.Width, p_ImgSource.Height, p_ImgSource.PixelFormat);
Graphics g = Graphics.FromImage(bmpCanvas);
g.DrawImage(p_ImgSource, new Rectangle(Point.Empty, bmpCanvas.Size),
0, 0,
p_ImgSource.Width, p_ImgSource.Height,
GraphicsUnit.Pixel, imgAttr);
// Liberamos recursos
g.Dispose();
imgAttr.Dispose();
// Retornamos la imagen con el filtro aplicado
return bmpCanvas;
}
Now what we need is an algorithm that captures the image obtained and calculates the rectangle of cuts that we are looking for.
It could be optimized and improved, but for the matter I created it as follows:private Rectangle ObtenerBordes(Bitmap p_Bmp)
{
int bordeIZQ = -1;
int bordeDER = -1;
int bordeSUP = -1;
int bordeINF = -1;
// Buscamos el borde SUPERIOR e INFERIOR
for (int y = 0; y < p_Bmp.Height; y++)
{
for (int x = 0; x < p_Bmp.Width; x++)
{
if (bordeSUP == -1)
{
Color pixel = p_Bmp.GetPixel(x, y);
if (pixel.Name != "ffffffff")
bordeSUP = y;
}
if (bordeINF == -1)
{
Color pixel = p_Bmp.GetPixel(x, p_Bmp.Height - y-1);
if (pixel.Name !="ffffffff")
bordeINF = p_Bmp.Height - y - 1;
}
}
if (bordeSUP != -1 && bordeINF != -1) break;
}
// Buscamos el borde DERECHO e IZQUIERDO
for (int x = 0; x < p_Bmp.Width; x++)
{
for (int y = 0; y < p_Bmp.Height; y++)
{
if (bordeIZQ == -1)
{
Color pixel = p_Bmp.GetPixel(x, y);
if (pixel.Name != "ffffffff")
bordeIZQ = x;
}
if (bordeDER == -1)
{
Color pixel = p_Bmp.GetPixel(p_Bmp.Width - x - 1, y);
if (pixel.Name != "ffffffff")
bordeDER = p_Bmp.Width - x - 1;
}
}
if (bordeIZQ != -1 && bordeDER != -1) break;
}
return new Rectangle(bordeIZQ, bordeSUP, bordeDER - bordeIZQ, bordeINF - bordeSUP);
}
Note that the only thing I do is go around the image until you find a pixel that is different from BLANCO and then set the edge on that coordinate.We already have all the work done, just add it to a function that will be the one we will call directly to get the cut of the image:private Image RecortarImage(Image p_ImgSource)
{
// Aplicamos un filtro a la imagen y retornamos el
// resultado a nuestro bitmap
// He bajado el brillo a la mitad y aumentado a 6 el contraste
// lo que me ha permitido obtener un resultado adecuado al menos
// con tu imagen de prueba.
Bitmap bmpCanvas = AplicaFiltroContrasteBrillo(p_ImgSource, 6f, 0.5f);
// Llamamos a la siguiente función que le pasaremos el Bitmap que hemos
// creado con la imagen y que ya tiene un contraste alto para hallar los bordes
Rectangle imgRectRecorte = ObtenerBordes(bmpCanvas);
// Una vez calculado el rectángulo de recorte creamos un Bitmap para copiar
// desde la imagen original a dicho bitmap la porción de imagen correspondiente
// según el rectángulo de recorte calculado.
Bitmap bmpCROP = new Bitmap(imgRectRecorte.Width, imgRectRecorte.Height);
Graphics gCrop = Graphics.FromImage(bmpCROP);
gCrop.DrawImage(p_ImgSource, new Rectangle(Point.Empty, bmpCROP.Size),
imgRectRecorte, GraphicsUnit.Pixel);
// Nos aseguramos de liberar recursos
gCrop.Dispose();
// Retornamos la imagen recortada
return bmpCROP;
}