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 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", ".webp", ".bmp", ".jpg", ".png", ".tif");
@ -91,11 +91,11 @@ namespace ImageProcessor.PlayGround
//.BackgroundColor(Color.Cyan)
//.ReplaceColor(Color.FromArgb(255, 223, 224), Color.FromArgb(121, 188, 255), 128)
//.Resize(size)
.Resize(new ResizeLayer(size, ResizeMode.Max))
//.Resize(new ResizeLayer(size, ResizeMode.Max))
// .Resize(new ResizeLayer(size, ResizeMode.Stretch))
//.DetectEdges(new SobelEdgeFilter(), true)
//.DetectEdges(new Laplacian3X3EdgeFilter(), true)
//.DetectEdges(new LaplacianOfGaussianEdgeFilter())
//.EntropyCrop()
.EntropyCrop()
//.Filter(MatrixFilters.Invert)
//.Contrast(50)
//.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 (c) James South.
// Licensed under the Apache License, Version 2.0.
// // Licensed under the Apache License, Version 2.0.
// </copyright>
// <summary>
// Performs binary threshold filtering against a given greyscale image.
// </summary>
// --------------------------------------------------------------------------------------------------------------------
namespace ImageProcessor.Imaging.Filters.Binarization
{
using System.Drawing;
using System.Drawing.Imaging;
using System.Threading.Tasks;
using ImageProcessor.Imaging.Filters.Photo;
/// <summary>
/// Performs binary threshold filtering against a given greyscale image.
/// </summary>
@ -24,7 +17,7 @@ namespace ImageProcessor.Imaging.Filters.Binarization
/// <summary>
/// The threshold value.
/// </summary>
private byte threshold = 10;
private byte threshold;
/// <summary>
/// Initializes a new instance of the <see cref="BinaryThreshold"/> class.
@ -32,7 +25,7 @@ namespace ImageProcessor.Imaging.Filters.Binarization
/// <param name="threshold">
/// The threshold.
/// </param>
public BinaryThreshold(byte threshold)
public BinaryThreshold(byte threshold = 10)
{
this.threshold = threshold;
}
@ -56,8 +49,12 @@ namespace ImageProcessor.Imaging.Filters.Binarization
/// <summary>
/// Processes the given bitmap to apply the threshold.
/// </summary>
/// <param name="source">The image to process.</param>
/// <returns>A processed bitmap.</returns>
/// <param name="source">
/// The image to process.
/// </param>
/// <returns>
/// A processed bitmap.
/// </returns>
public Bitmap ProcessFilter(Bitmap source)
{
int width = source.Width;
@ -66,8 +63,8 @@ namespace ImageProcessor.Imaging.Filters.Binarization
using (FastBitmap sourceBitmap = new FastBitmap(source))
{
Parallel.For(
0,
height,
0,
height,
y =>
{
for (int x = 0; x < width; x++)
@ -75,6 +72,7 @@ namespace ImageProcessor.Imaging.Filters.Binarization
// ReSharper disable AccessToDisposedClosure
Color color = sourceBitmap.GetPixel(x, y);
sourceBitmap.SetPixel(x, y, color.B >= this.threshold ? Color.White : Color.Black);
// ReSharper restore AccessToDisposedClosure
}
});

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

@ -12,6 +12,7 @@ namespace ImageProcessor.Imaging.Filters.EdgeDetection
{
using System;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Drawing.Imaging;
using System.Threading.Tasks;
@ -57,29 +58,42 @@ namespace ImageProcessor.Imaging.Filters.EdgeDetection
{
int width = source.Width;
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 input = new Bitmap(width, height);
Bitmap input = new Bitmap(bufferedWidth, bufferedHeight);
destination.SetResolution(source.HorizontalResolution, source.VerticalResolution);
input.SetResolution(source.HorizontalResolution, source.VerticalResolution);
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);
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.
using (ImageAttributes attributes = new ImageAttributes())
if (this.greyscale)
{
attributes.SetColorMatrix(ColorMatrixes.GreyScale);
graphics.DrawImage(source, rectangle, 0, 0, width, height, GraphicsUnit.Pixel, attributes);
}
}
else
{
// Fixes an issue with transparency not converting properly.
graphics.Clear(Color.Transparent);
graphics.DrawImage(source, rectangle);
// 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.
// Later on we draw pixels without that excess.
using (TextureBrush tb = new TextureBrush(source, rectangle, attributes))
{
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.
Parallel.For(
0,
height,
bufferedHeight,
y =>
{
for (int x = 0; x < width; x++)
for (int x = 0; x < bufferedWidth; x++)
{
double rX = 0;
double gX = 0;
@ -119,7 +133,7 @@ namespace ImageProcessor.Imaging.Filters.EdgeDetection
}
// Outwith the current bounds so break.
if (offsetY >= height)
if (offsetY >= bufferedHeight)
{
break;
}
@ -135,7 +149,7 @@ namespace ImageProcessor.Imaging.Filters.EdgeDetection
continue;
}
if (offsetX < width)
if (offsetX < bufferedWidth)
{
// ReSharper disable once AccessToDisposedClosure
Color currentColor = sourceBitmap.GetPixel(offsetX, offsetY);
@ -158,8 +172,11 @@ namespace ImageProcessor.Imaging.Filters.EdgeDetection
byte blue = bX.ToByte();
Color newColor = Color.FromArgb(red, green, blue);
// ReSharper disable once AccessToDisposedClosure
destinationBitmap.SetPixel(x, y, newColor);
if (y > 0 && x > 0 && y < maxHeight && x < maxWidth)
{
// ReSharper disable once AccessToDisposedClosure
destinationBitmap.SetPixel(x - 1, y - 1, newColor);
}
}
});
}
@ -171,17 +188,6 @@ namespace ImageProcessor.Imaging.Filters.EdgeDetection
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;
}
@ -194,29 +200,42 @@ namespace ImageProcessor.Imaging.Filters.EdgeDetection
{
int width = source.Width;
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 input = new Bitmap(width, height);
Bitmap input = new Bitmap(bufferedWidth, bufferedHeight);
destination.SetResolution(source.HorizontalResolution, source.VerticalResolution);
input.SetResolution(source.HorizontalResolution, source.VerticalResolution);
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);
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.
using (ImageAttributes attributes = new ImageAttributes())
if (this.greyscale)
{
attributes.SetColorMatrix(ColorMatrixes.GreyScale);
graphics.DrawImage(source, rectangle, 0, 0, width, height, GraphicsUnit.Pixel, attributes);
}
}
else
{
// Fixes an issue with transparency not converting properly.
graphics.Clear(Color.Transparent);
graphics.DrawImage(source, rectangle);
// 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.
// Later on we draw pixels without that excess.
using (TextureBrush tb = new TextureBrush(source, rectangle, attributes))
{
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.
Parallel.For(
0,
height,
bufferedHeight,
y =>
{
for (int x = 0; x < width; x++)
for (int x = 0; x < bufferedWidth; x++)
{
double rX = 0;
double rY = 0;
@ -260,7 +279,7 @@ namespace ImageProcessor.Imaging.Filters.EdgeDetection
}
// Outwith the current bounds so break.
if (offsetY >= height)
if (offsetY >= bufferedHeight)
{
break;
}
@ -276,7 +295,7 @@ namespace ImageProcessor.Imaging.Filters.EdgeDetection
continue;
}
if (offsetX < width)
if (offsetX < bufferedWidth)
{
// ReSharper disable once AccessToDisposedClosure
Color currentColor = sourceBitmap.GetPixel(offsetX, offsetY);
@ -302,8 +321,11 @@ namespace ImageProcessor.Imaging.Filters.EdgeDetection
byte blue = Math.Sqrt((bX * bX) + (bY * bY)).ToByte();
Color newColor = Color.FromArgb(red, green, blue);
// ReSharper disable once AccessToDisposedClosure
destinationBitmap.SetPixel(x, y, newColor);
if (y > 0 && x > 0 && y < maxHeight && x < maxWidth)
{
// ReSharper disable once AccessToDisposedClosure
destinationBitmap.SetPixel(x - 1, y - 1, newColor);
}
}
});
}
@ -315,17 +337,6 @@ namespace ImageProcessor.Imaging.Filters.EdgeDetection
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;
}
}

Loading…
Cancel
Save