Browse Source

Entopy crop no longer overcrops

Former-commit-id: 0bffcc93394feb441b04a0c218bfc270c4e903c7
Former-commit-id: c1143b12dfcab33efe6596d619b6a823fa001a95
pull/17/head
James South 11 years ago
parent
commit
f720dcfd2c
  1. 8
      src/ImageProcessor.Playground/Program.cs
  2. 1
      src/ImageProcessor.Playground/images/input/bob_revolutionpro_wilderness_02_2013_72dpi_2000x2000.jpg.REMOVED.git-id
  3. 26
      src/ImageProcessor/Imaging/Filters/Binarization/BinaryThreshold.cs
  4. 123
      src/ImageProcessor/Imaging/Filters/EdgeDetection/ConvolutionFilter.cs

8
src/ImageProcessor.Playground/Program.cs

@ -50,7 +50,7 @@ namespace ImageProcessor.PlayGround
// Image mask = Image.FromFile(Path.Combine(resolvedPath, "mask.png")); // Image mask = Image.FromFile(Path.Combine(resolvedPath, "mask.png"));
// Image overlay = Image.FromFile(Path.Combine(resolvedPath, "imageprocessor.128.png")); // Image overlay = Image.FromFile(Path.Combine(resolvedPath, "imageprocessor.128.png"));
FileInfo fileInfo = new FileInfo(Path.Combine(resolvedPath, "test5.jpg")); FileInfo fileInfo = new FileInfo(Path.Combine(resolvedPath, "bob_revolutionpro_wilderness_02_2013_72dpi_2000x2000.jpg"));
IEnumerable<FileInfo> files = GetFilesByExtensions(di, ".gif"); IEnumerable<FileInfo> files = GetFilesByExtensions(di, ".gif");
//IEnumerable<FileInfo> files = GetFilesByExtensions(di, ".gif", ".webp", ".bmp", ".jpg", ".png", ".tif"); //IEnumerable<FileInfo> files = GetFilesByExtensions(di, ".gif", ".webp", ".bmp", ".jpg", ".png", ".tif");
@ -91,11 +91,11 @@ namespace ImageProcessor.PlayGround
//.BackgroundColor(Color.Cyan) //.BackgroundColor(Color.Cyan)
//.ReplaceColor(Color.FromArgb(255, 223, 224), Color.FromArgb(121, 188, 255), 128) //.ReplaceColor(Color.FromArgb(255, 223, 224), Color.FromArgb(121, 188, 255), 128)
//.Resize(size) //.Resize(size)
.Resize(new ResizeLayer(size, ResizeMode.Max)) //.Resize(new ResizeLayer(size, ResizeMode.Max))
// .Resize(new ResizeLayer(size, ResizeMode.Stretch)) // .Resize(new ResizeLayer(size, ResizeMode.Stretch))
//.DetectEdges(new SobelEdgeFilter(), true) //.DetectEdges(new Laplacian3X3EdgeFilter(), true)
//.DetectEdges(new LaplacianOfGaussianEdgeFilter()) //.DetectEdges(new LaplacianOfGaussianEdgeFilter())
//.EntropyCrop() .EntropyCrop()
//.Filter(MatrixFilters.Invert) //.Filter(MatrixFilters.Invert)
//.Contrast(50) //.Contrast(50)
//.Filter(MatrixFilters.Comic) //.Filter(MatrixFilters.Comic)

1
src/ImageProcessor.Playground/images/input/bob_revolutionpro_wilderness_02_2013_72dpi_2000x2000.jpg.REMOVED.git-id

@ -0,0 +1 @@
cfa62bc3b77a7efb16c25218c1381da5d4f36db7

26
src/ImageProcessor/Imaging/Filters/Binarization/BinaryThreshold.cs

@ -1,21 +1,14 @@
// -------------------------------------------------------------------------------------------------------------------- // --------------------------------------------------------------------------------------------------------------------
// <copyright file="BinaryThreshold.cs" company="James South"> // <copyright file="BinaryThreshold.cs" company="James South">
// Copyright (c) James South. // Copyright (c) James South.
// Licensed under the Apache License, Version 2.0. // // Licensed under the Apache License, Version 2.0.
// </copyright> // </copyright>
// <summary>
// Performs binary threshold filtering against a given greyscale image.
// </summary>
// -------------------------------------------------------------------------------------------------------------------- // --------------------------------------------------------------------------------------------------------------------
namespace ImageProcessor.Imaging.Filters.Binarization namespace ImageProcessor.Imaging.Filters.Binarization
{ {
using System.Drawing; using System.Drawing;
using System.Drawing.Imaging;
using System.Threading.Tasks; using System.Threading.Tasks;
using ImageProcessor.Imaging.Filters.Photo;
/// <summary> /// <summary>
/// Performs binary threshold filtering against a given greyscale image. /// Performs binary threshold filtering against a given greyscale image.
/// </summary> /// </summary>
@ -24,7 +17,7 @@ namespace ImageProcessor.Imaging.Filters.Binarization
/// <summary> /// <summary>
/// The threshold value. /// The threshold value.
/// </summary> /// </summary>
private byte threshold = 10; private byte threshold;
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="BinaryThreshold"/> class. /// Initializes a new instance of the <see cref="BinaryThreshold"/> class.
@ -32,7 +25,7 @@ namespace ImageProcessor.Imaging.Filters.Binarization
/// <param name="threshold"> /// <param name="threshold">
/// The threshold. /// The threshold.
/// </param> /// </param>
public BinaryThreshold(byte threshold) public BinaryThreshold(byte threshold = 10)
{ {
this.threshold = threshold; this.threshold = threshold;
} }
@ -56,8 +49,12 @@ namespace ImageProcessor.Imaging.Filters.Binarization
/// <summary> /// <summary>
/// Processes the given bitmap to apply the threshold. /// Processes the given bitmap to apply the threshold.
/// </summary> /// </summary>
/// <param name="source">The image to process.</param> /// <param name="source">
/// <returns>A processed bitmap.</returns> /// The image to process.
/// </param>
/// <returns>
/// A processed bitmap.
/// </returns>
public Bitmap ProcessFilter(Bitmap source) public Bitmap ProcessFilter(Bitmap source)
{ {
int width = source.Width; int width = source.Width;
@ -66,8 +63,8 @@ namespace ImageProcessor.Imaging.Filters.Binarization
using (FastBitmap sourceBitmap = new FastBitmap(source)) using (FastBitmap sourceBitmap = new FastBitmap(source))
{ {
Parallel.For( Parallel.For(
0, 0,
height, height,
y => y =>
{ {
for (int x = 0; x < width; x++) for (int x = 0; x < width; x++)
@ -75,6 +72,7 @@ namespace ImageProcessor.Imaging.Filters.Binarization
// ReSharper disable AccessToDisposedClosure // ReSharper disable AccessToDisposedClosure
Color color = sourceBitmap.GetPixel(x, y); Color color = sourceBitmap.GetPixel(x, y);
sourceBitmap.SetPixel(x, y, color.B >= this.threshold ? Color.White : Color.Black); sourceBitmap.SetPixel(x, y, color.B >= this.threshold ? Color.White : Color.Black);
// ReSharper restore AccessToDisposedClosure // ReSharper restore AccessToDisposedClosure
} }
}); });

123
src/ImageProcessor/Imaging/Filters/EdgeDetection/ConvolutionFilter.cs

@ -12,6 +12,7 @@ namespace ImageProcessor.Imaging.Filters.EdgeDetection
{ {
using System; using System;
using System.Drawing; using System.Drawing;
using System.Drawing.Drawing2D;
using System.Drawing.Imaging; using System.Drawing.Imaging;
using System.Threading.Tasks; using System.Threading.Tasks;
@ -57,29 +58,42 @@ namespace ImageProcessor.Imaging.Filters.EdgeDetection
{ {
int width = source.Width; int width = source.Width;
int height = source.Height; int height = source.Height;
int maxWidth = width + 1;
int maxHeight = height + 1;
int bufferedWidth = width + 2;
int bufferedHeight = height + 2;
Bitmap destination = new Bitmap(width, height); Bitmap destination = new Bitmap(width, height);
Bitmap input = new Bitmap(width, height); Bitmap input = new Bitmap(bufferedWidth, bufferedHeight);
destination.SetResolution(source.HorizontalResolution, source.VerticalResolution); destination.SetResolution(source.HorizontalResolution, source.VerticalResolution);
input.SetResolution(source.HorizontalResolution, source.VerticalResolution); input.SetResolution(source.HorizontalResolution, source.VerticalResolution);
using (Graphics graphics = Graphics.FromImage(input)) using (Graphics graphics = Graphics.FromImage(input))
{ {
// Fixes an issue with transparency not converting properly.
graphics.Clear(Color.Transparent);
Rectangle destinationRectangle = new Rectangle(0, 0, bufferedWidth, bufferedHeight);
Rectangle rectangle = new Rectangle(0, 0, width, height); Rectangle rectangle = new Rectangle(0, 0, width, height);
if (this.greyscale)
// If it's greyscale apply a colormatrix to the image.
using (ImageAttributes attributes = new ImageAttributes())
{ {
// If it's greyscale apply a colormatrix to the image. if (this.greyscale)
using (ImageAttributes attributes = new ImageAttributes())
{ {
attributes.SetColorMatrix(ColorMatrixes.GreyScale); attributes.SetColorMatrix(ColorMatrixes.GreyScale);
graphics.DrawImage(source, rectangle, 0, 0, width, height, GraphicsUnit.Pixel, attributes);
} }
}
else // We use a trick here to detect right to the edges of the image.
{ // flip/tile the image with a pixel in excess in each direction to duplicate pixels.
// Fixes an issue with transparency not converting properly. // Later on we draw pixels without that excess.
graphics.Clear(Color.Transparent); using (TextureBrush tb = new TextureBrush(source, rectangle, attributes))
graphics.DrawImage(source, rectangle); {
tb.WrapMode = WrapMode.TileFlipXY;
tb.TranslateTransform(1, 1);
graphics.FillRectangle(tb, destinationRectangle);
}
} }
} }
@ -97,10 +111,10 @@ namespace ImageProcessor.Imaging.Filters.EdgeDetection
// Loop through the pixels. // Loop through the pixels.
Parallel.For( Parallel.For(
0, 0,
height, bufferedHeight,
y => y =>
{ {
for (int x = 0; x < width; x++) for (int x = 0; x < bufferedWidth; x++)
{ {
double rX = 0; double rX = 0;
double gX = 0; double gX = 0;
@ -119,7 +133,7 @@ namespace ImageProcessor.Imaging.Filters.EdgeDetection
} }
// Outwith the current bounds so break. // Outwith the current bounds so break.
if (offsetY >= height) if (offsetY >= bufferedHeight)
{ {
break; break;
} }
@ -135,7 +149,7 @@ namespace ImageProcessor.Imaging.Filters.EdgeDetection
continue; continue;
} }
if (offsetX < width) if (offsetX < bufferedWidth)
{ {
// ReSharper disable once AccessToDisposedClosure // ReSharper disable once AccessToDisposedClosure
Color currentColor = sourceBitmap.GetPixel(offsetX, offsetY); Color currentColor = sourceBitmap.GetPixel(offsetX, offsetY);
@ -158,8 +172,11 @@ namespace ImageProcessor.Imaging.Filters.EdgeDetection
byte blue = bX.ToByte(); byte blue = bX.ToByte();
Color newColor = Color.FromArgb(red, green, blue); Color newColor = Color.FromArgb(red, green, blue);
// ReSharper disable once AccessToDisposedClosure if (y > 0 && x > 0 && y < maxHeight && x < maxWidth)
destinationBitmap.SetPixel(x, y, newColor); {
// ReSharper disable once AccessToDisposedClosure
destinationBitmap.SetPixel(x - 1, y - 1, newColor);
}
} }
}); });
} }
@ -171,17 +188,6 @@ namespace ImageProcessor.Imaging.Filters.EdgeDetection
input.Dispose(); input.Dispose();
} }
// Draw a black rectangle around the area to ensure that the first row/column in covered.
using (Graphics graphics = Graphics.FromImage(destination))
{
// Draw an edge around the image.
using (Pen blackPen = new Pen(Color.Black))
{
blackPen.Width = 4;
graphics.DrawRectangle(blackPen, new Rectangle(0, 0, destination.Width, destination.Height));
}
}
return destination; return destination;
} }
@ -194,29 +200,42 @@ namespace ImageProcessor.Imaging.Filters.EdgeDetection
{ {
int width = source.Width; int width = source.Width;
int height = source.Height; int height = source.Height;
int maxWidth = width + 1;
int maxHeight = height + 1;
int bufferedWidth = width + 2;
int bufferedHeight = height + 2;
Bitmap destination = new Bitmap(width, height); Bitmap destination = new Bitmap(width, height);
Bitmap input = new Bitmap(width, height); Bitmap input = new Bitmap(bufferedWidth, bufferedHeight);
destination.SetResolution(source.HorizontalResolution, source.VerticalResolution); destination.SetResolution(source.HorizontalResolution, source.VerticalResolution);
input.SetResolution(source.HorizontalResolution, source.VerticalResolution); input.SetResolution(source.HorizontalResolution, source.VerticalResolution);
using (Graphics graphics = Graphics.FromImage(input)) using (Graphics graphics = Graphics.FromImage(input))
{ {
// Fixes an issue with transparency not converting properly.
graphics.Clear(Color.Transparent);
Rectangle destinationRectangle = new Rectangle(0, 0, bufferedWidth, bufferedHeight);
Rectangle rectangle = new Rectangle(0, 0, width, height); Rectangle rectangle = new Rectangle(0, 0, width, height);
if (this.greyscale)
// If it's greyscale apply a colormatrix to the image.
using (ImageAttributes attributes = new ImageAttributes())
{ {
// If it's greyscale apply a colormatrix to the image. if (this.greyscale)
using (ImageAttributes attributes = new ImageAttributes())
{ {
attributes.SetColorMatrix(ColorMatrixes.GreyScale); attributes.SetColorMatrix(ColorMatrixes.GreyScale);
graphics.DrawImage(source, rectangle, 0, 0, width, height, GraphicsUnit.Pixel, attributes);
} }
}
else // We use a trick here to detect right to the edges of the image.
{ // flip/tile the image with a pixel in excess in each direction to duplicate pixels.
// Fixes an issue with transparency not converting properly. // Later on we draw pixels without that excess.
graphics.Clear(Color.Transparent); using (TextureBrush tb = new TextureBrush(source, rectangle, attributes))
graphics.DrawImage(source, rectangle); {
tb.WrapMode = WrapMode.TileFlipXY;
tb.TranslateTransform(1, 1);
graphics.FillRectangle(tb, destinationRectangle);
}
} }
} }
@ -235,10 +254,10 @@ namespace ImageProcessor.Imaging.Filters.EdgeDetection
// Loop through the pixels. // Loop through the pixels.
Parallel.For( Parallel.For(
0, 0,
height, bufferedHeight,
y => y =>
{ {
for (int x = 0; x < width; x++) for (int x = 0; x < bufferedWidth; x++)
{ {
double rX = 0; double rX = 0;
double rY = 0; double rY = 0;
@ -260,7 +279,7 @@ namespace ImageProcessor.Imaging.Filters.EdgeDetection
} }
// Outwith the current bounds so break. // Outwith the current bounds so break.
if (offsetY >= height) if (offsetY >= bufferedHeight)
{ {
break; break;
} }
@ -276,7 +295,7 @@ namespace ImageProcessor.Imaging.Filters.EdgeDetection
continue; continue;
} }
if (offsetX < width) if (offsetX < bufferedWidth)
{ {
// ReSharper disable once AccessToDisposedClosure // ReSharper disable once AccessToDisposedClosure
Color currentColor = sourceBitmap.GetPixel(offsetX, offsetY); Color currentColor = sourceBitmap.GetPixel(offsetX, offsetY);
@ -302,8 +321,11 @@ namespace ImageProcessor.Imaging.Filters.EdgeDetection
byte blue = Math.Sqrt((bX * bX) + (bY * bY)).ToByte(); byte blue = Math.Sqrt((bX * bX) + (bY * bY)).ToByte();
Color newColor = Color.FromArgb(red, green, blue); Color newColor = Color.FromArgb(red, green, blue);
// ReSharper disable once AccessToDisposedClosure if (y > 0 && x > 0 && y < maxHeight && x < maxWidth)
destinationBitmap.SetPixel(x, y, newColor); {
// ReSharper disable once AccessToDisposedClosure
destinationBitmap.SetPixel(x - 1, y - 1, newColor);
}
} }
}); });
} }
@ -315,17 +337,6 @@ namespace ImageProcessor.Imaging.Filters.EdgeDetection
input.Dispose(); input.Dispose();
} }
// Draw a black rectangle around the area to ensure that the first row/column in covered.
using (Graphics graphics = Graphics.FromImage(destination))
{
// Draw an edge around the image.
using (Pen blackPen = new Pen(Color.Black))
{
blackPen.Width = 4;
graphics.DrawRectangle(blackPen, new Rectangle(0, 0, destination.Width, destination.Height));
}
}
return destination; return destination;
} }
} }

Loading…
Cancel
Save