Browse Source

Refactoring entropy crop

Former-commit-id: f6d222bdb990035f155162523ac8d2eaab7e57e9
Former-commit-id: 2cc168df666dc13196df282de960242e2db5785a
pull/17/head
James South 11 years ago
parent
commit
5db89f4cbf
  1. 6
      src/ImageProcessor.Playground/Program.cs
  2. 1
      src/ImageProcessor/ImageProcessor.csproj
  3. 38
      src/ImageProcessor/Imaging/Colors/RgbaComponent.cs
  4. 120
      src/ImageProcessor/Imaging/Helpers/ImageMaths.cs
  5. 7
      src/ImageProcessor/Imaging/PixelData.cs
  6. 104
      src/ImageProcessor/Processors/EntropyCrop.cs

6
src/ImageProcessor.Playground/Program.cs

@ -50,7 +50,7 @@ namespace ImageProcessor.PlayGround
}
Image mask = Image.FromFile(Path.Combine(resolvedPath, "mask.png"));
IEnumerable<FileInfo> files = GetFilesByExtensions(di, ".jpg");
IEnumerable<FileInfo> files = GetFilesByExtensions(di, ".png");
//IEnumerable<FileInfo> files = GetFilesByExtensions(di, ".gif", ".webp", ".bmp", ".jpg", ".png", ".tif");
foreach (FileInfo fileInfo in files)
@ -85,9 +85,9 @@ namespace ImageProcessor.PlayGround
//.Resize(layer)
//.DetectEdges(new SobelEdgeFilter(), false)
//.DetectEdges(new LaplacianOfGaussianEdgeFilter())
//.EntropyCrop()
.EntropyCrop()
//.Filter(MatrixFilters.Invert)
.Filter(MatrixFilters.Comic)
//.Filter(MatrixFilters.Comic)
//.Filter(MatrixFilters.HiSatch)
//.Pixelate(8)
//.GaussianSharpen(10)

1
src/ImageProcessor/ImageProcessor.csproj

@ -133,6 +133,7 @@
<Compile Include="Configuration\NativeMethods.cs" />
<Compile Include="Imaging\Colors\HslaColor.cs" />
<Compile Include="Imaging\Colors\RgbaColor.cs" />
<Compile Include="Imaging\Colors\RgbaComponent.cs" />
<Compile Include="Imaging\Colors\YCbCrColor.cs" />
<Compile Include="Imaging\Filters\Artistic\OilPaintingFilter.cs" />
<Compile Include="Imaging\Filters\EdgeDetection\ConvolutionFilter.cs" />

38
src/ImageProcessor/Imaging/Colors/RgbaComponent.cs

@ -0,0 +1,38 @@
// --------------------------------------------------------------------------------------------------------------------
// <copyright file="RgbaComponent.cs" company="James South">
// Copyright (c) James South.
// Licensed under the Apache License, Version 2.0.
// </copyright>
// <summary>
// Enumerates the RGBA (red, green, blue, alpha) color components.
// </summary>
// --------------------------------------------------------------------------------------------------------------------
namespace ImageProcessor.Imaging.Colors
{
/// <summary>
/// Enumerates the RGBA (red, green, blue, alpha) color components.
/// </summary>
public enum RgbaComponent
{
/// <summary>
/// The blue component.
/// </summary>
B = 0,
/// <summary>
/// The green component.
/// </summary>
G = 1,
/// <summary>
/// The red component.
/// </summary>
R = 2,
/// <summary>
/// The alpha component.
/// </summary>
A = 3
}
}

120
src/ImageProcessor/Imaging/Helpers/ImageMaths.cs

@ -10,8 +10,11 @@
namespace ImageProcessor.Imaging.Helpers
{
using System;
using System.Drawing;
using ImageProcessor.Imaging.Colors;
/// <summary>
/// Provides reusable mathematical methods to apply to images.
/// </summary>
@ -34,6 +37,123 @@ namespace ImageProcessor.Imaging.Helpers
return new Rectangle(topLeft.X, topLeft.Y, bottomRight.X - topLeft.X, bottomRight.Y - topLeft.Y);
}
/// <summary>
/// Finds the bounding rectangle based on the first instance of any color component other
/// than the given one.
/// </summary>
/// <param name="bitmap">
/// The <see cref="Image"/> to search within.
/// </param>
/// <param name="componentValue">
/// The color component value to remove.
/// </param>
/// <param name="channel">
/// The <see cref="RgbaComponent"/> channel to test against.
/// </param>
/// <returns>
/// The <see cref="Rectangle"/>.
/// </returns>
public static Rectangle GetFilteredBoundingRectangle(Image bitmap, byte componentValue, RgbaComponent channel = RgbaComponent.B)
{
int width = bitmap.Width;
int height = bitmap.Height;
Point topLeft = new Point();
Point bottomRight = new Point();
Func<FastBitmap, int, int, byte, bool> delegateFunc;
// Determine which channel to check against
switch (channel)
{
case RgbaComponent.R:
delegateFunc = (fastBitmap, x, y, b) => fastBitmap.GetPixel(x, y).R != b;
break;
case RgbaComponent.G:
delegateFunc = (fastBitmap, x, y, b) => fastBitmap.GetPixel(x, y).G != b;
break;
case RgbaComponent.A:
delegateFunc = (fastBitmap, x, y, b) => fastBitmap.GetPixel(x, y).A != b;
break;
default:
delegateFunc = (fastBitmap, x, y, b) => fastBitmap.GetPixel(x, y).B != b;
break;
}
Func<FastBitmap, int> getMinY = fastBitmap =>
{
for (int y = 0; y < height; y++)
{
for (int x = 0; x < width; x++)
{
if (delegateFunc(fastBitmap, x, y, componentValue))
{
return y;
}
}
}
return 0;
};
Func<FastBitmap, int> getMaxY = fastBitmap =>
{
for (int y = height - 1; y > -1; y--)
{
for (int x = 0; x < width; x++)
{
if (delegateFunc(fastBitmap, x, y, componentValue))
{
return y;
}
}
}
return height;
};
Func<FastBitmap, int> getMinX = fastBitmap =>
{
for (int x = 0; x < width; x++)
{
for (int y = 0; y < height; y++)
{
if (delegateFunc(fastBitmap, x, y, componentValue))
{
return x;
}
}
}
return 0;
};
Func<FastBitmap, int> getMaxX = fastBitmap =>
{
for (int x = width - 1; x > -1; x--)
{
for (int y = 0; y < height; y++)
{
if (delegateFunc(fastBitmap, x, y, componentValue))
{
return x;
}
}
}
return height;
};
using (FastBitmap fastBitmap = new FastBitmap(bitmap))
{
topLeft.Y = getMinY(fastBitmap) + 1;
topLeft.X = getMinX(fastBitmap) + 1;
bottomRight.Y = getMaxY(fastBitmap);
bottomRight.X = getMaxX(fastBitmap);
}
return ImageMaths.GetBoundingRectangle(topLeft, bottomRight);
}
/// <summary>
/// Gets a <see cref="Rectangle"/> representing the child centered relative to the parent.
/// </summary>

7
src/ImageProcessor/Imaging/PixelData.cs

@ -10,29 +10,36 @@
namespace ImageProcessor.Imaging
{
using System.Runtime.InteropServices;
/// <summary>
/// Contains the component parts that make up a single pixel.
/// </summary>
[StructLayout(LayoutKind.Explicit)]
public struct PixelData
{
/// <summary>
/// The blue component.
/// </summary>
[FieldOffset(0)]
public byte B;
/// <summary>
/// The green component.
/// </summary>
[FieldOffset(1)]
public byte G;
/// <summary>
/// The red component.
/// </summary>
[FieldOffset(2)]
public byte R;
/// <summary>
/// The alpha component.
/// </summary>
[FieldOffset(3)]
public byte A;
/// <summary>

104
src/ImageProcessor/Processors/EntropyCrop.cs

@ -12,9 +12,9 @@ namespace ImageProcessor.Processors
using System.Drawing;
using ImageProcessor.Common.Exceptions;
using ImageProcessor.Imaging;
using ImageProcessor.Imaging.Filters.Binarization;
using ImageProcessor.Imaging.Filters.EdgeDetection;
using ImageProcessor.Imaging.Helpers;
/// <summary>
/// Performs a crop on an image to the area of greatest entropy.
@ -61,8 +61,9 @@ namespace ImageProcessor.Processors
// Detect the edges then strip out middle shades.
grey = new ConvolutionFilter(new SobelEdgeFilter(), true).Process2DFilter(image);
grey = new BinaryThreshold(threshold).ProcessFilter(grey);
Rectangle rectangle = this.FindBoundingBox(grey, 0);
// Search for the first white pixels
Rectangle rectangle = ImageMaths.GetFilteredBoundingRectangle(grey, 0);
newImage = new Bitmap(rectangle.Width, rectangle.Height);
using (Graphics graphics = Graphics.FromImage(newImage))
@ -99,102 +100,5 @@ namespace ImageProcessor.Processors
return image;
}
/// <summary>
/// Finds the bounding rectangle based on the first instance of any color component other
/// than the given one.
/// </summary>
/// <param name="bitmap">
/// The bitmap.
/// </param>
/// <param name="componentToRemove">
/// The color component to remove.
/// </param>
/// <returns>
/// The <see cref="Rectangle"/>.
/// </returns>
private Rectangle FindBoundingBox(Bitmap bitmap, byte componentToRemove)
{
int width = bitmap.Width;
int height = bitmap.Height;
int startX;
int startY;
int stopX;
int stopY;
Func<FastBitmap, int> getMinY = fastBitmap =>
{
for (int y = 0; y < height; y++)
{
for (int x = 0; x < width; x++)
{
if (fastBitmap.GetPixel(x, y).B != componentToRemove)
{
return y;
}
}
}
return 0;
};
Func<FastBitmap, int> getMaxY = fastBitmap =>
{
for (int y = height - 1; y > -1; y--)
{
for (int x = 0; x < width; x++)
{
if (fastBitmap.GetPixel(x, y).B != componentToRemove)
{
return y;
}
}
}
return height;
};
Func<FastBitmap, int> getMinX = fastBitmap =>
{
for (int x = 0; x < width; x++)
{
for (int y = 0; y < height; y++)
{
if (fastBitmap.GetPixel(x, y).B != componentToRemove)
{
return x;
}
}
}
return 0;
};
Func<FastBitmap, int> getMaxX = fastBitmap =>
{
for (int x = width - 1; x > -1; x--)
{
for (int y = 0; y < height; y++)
{
if (fastBitmap.GetPixel(x, y).B != componentToRemove)
{
return x;
}
}
}
return height;
};
using (FastBitmap fastBitmap = new FastBitmap(bitmap))
{
startY = getMinY(fastBitmap);
stopY = getMaxY(fastBitmap);
startX = getMinX(fastBitmap);
stopX = getMaxX(fastBitmap);
}
return new Rectangle(startX + 1, startY + 1, stopX - (startX + 1), stopY - (startY + 1));
}
}
}
Loading…
Cancel
Save