You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 

261 lines
9.2 KiB

//----------------------------------------------------------------------------
// Copyright (C) 2004-2018 by EMGU Corporation. All rights reserved.
//----------------------------------------------------------------------------
using System;
using System.Drawing;
using System.Runtime.InteropServices;
using System.Windows.Forms;
using Emgu.CV.CvEnum;
using ZedGraph;
using Emgu.CV;
using Emgu.CV.Structure;
using Emgu.Util;
using System.Diagnostics;
namespace Emgu.CV.UI
{
/// <summary>
/// The control that is used to display histogram
/// </summary>
public partial class HistogramBox : UserControl
{
private Graphics _graphic;
/// <summary>
/// Construct a histogram control
/// </summary>
public HistogramBox()
{
InitializeComponent();
#region Setup the graph
// First, clear out any old GraphPane's from the MasterPane collection
MasterPane master = zedGraphControl1.MasterPane;
master.PaneList.Clear();
// Display the MasterPane Title, and set the outer margin to 10 points
master.Title.IsVisible = true;
master.Title.Text = Properties.StringTable.DefaultHistogramTitle;
master.Margin.All = 10;
#endregion
// Layout the GraphPanes using a default Pane Layout
_graphic = CreateGraphics();
// Size the control to fill the form with a margin
SetSize();
}
private void HistogramViewer_Resize(object sender, EventArgs e)
{
SetSize();
}
// SetSize() is separate from Resize() so we can
// call it independently from the Form1_Load() method
// This leaves a 10 px margin around the outside of the control
// Customize this to fit your needs
private void SetSize()
{
zedGraphControl1.Location = new Point(10, 10);
// Leave a small margin around the outside of the control
zedGraphControl1.Size = new Size(ClientRectangle.Width - 20,
ClientRectangle.Height - 20);
}
/// <summary>
/// Get the zedgraph control from this histogram control
/// </summary>
public ZedGraphControl ZedGraphControl
{
get
{
return zedGraphControl1;
}
}
/// <summary>
/// Add a plot of the 1D histogram. You should call the Refresh() function to update the control after all modification is complete.
/// </summary>
/// <param name="name">The name of the histogram</param>
/// <param name="color">The drawing color</param>
/// <param name="histogram">The 1D histogram to be drawn</param>
/// <param name="binSize">The size of the bin</param>
/// <param name="ranges">The ranges</param>
public void AddHistogram(String name, Color color, Mat histogram, int binSize, float[] ranges)
{
//Debug.Assert(histogram.Dimension == 1, Properties.StringTable.Only1DHistogramSupported);
GraphPane pane = new GraphPane();
// Set the Title
pane.Title.Text = name;
pane.XAxis.Title.Text = Properties.StringTable.Value;
pane.YAxis.Title.Text = Properties.StringTable.Count;
#region draw the histogram
RangeF range = new RangeF(ranges[0], ranges[1]);
float step = (range.Max - range.Min) / binSize;
float start = range.Min;
double[] bin = new double[binSize];
for (int binIndex = 0; binIndex < binSize; binIndex++)
{
bin[binIndex] = start;
start += step;
}
double[] binVal = new double[histogram.Size.Height];
GCHandle handle = GCHandle.Alloc(binVal, GCHandleType.Pinned);
using (Matrix<double> m = new Matrix<double>(binVal.Length, 1, handle.AddrOfPinnedObject(), sizeof(double)))
{
histogram.ConvertTo(m, DepthType.Cv64F);
PointPairList pointList = new PointPairList(
bin,
binVal);
pane.AddCurve(name, pointList, color);
}
handle.Free();
#endregion
zedGraphControl1.MasterPane.Add(pane);
}
/// <summary>
/// Generate histograms for the image. One histogram is generated for each color channel.
/// You will need to call the Refresh function to do the painting afterward.
/// </summary>
/// <param name="image">The image to generate histogram from</param>
/// <param name="numberOfBins">The number of bins for each histogram</param>
public void GenerateHistograms(IImage image, int numberOfBins)
{
Mat[] channels = new Mat[image.NumberOfChannels];
Type imageType;
if ((imageType = Toolbox.GetBaseType(image.GetType(), "Image`2")) != null
|| (imageType = Toolbox.GetBaseType(image.GetType(), "Mat")) != null
|| (imageType = Toolbox.GetBaseType(image.GetType(), "UMat")) != null)
{
for (int i = 0; i < image.NumberOfChannels; i++)
{
Mat channel = new Mat();
CvInvoke.ExtractChannel(image, channel, i);
channels[i] = channel;
}
}
else if ((imageType = Toolbox.GetBaseType(image.GetType(), "CudaImage`2")) != null)
{
IImage img = imageType.GetMethod("ToImage").Invoke(image, null) as IImage;
for (int i = 0; i < img.NumberOfChannels; i++)
{
Mat channel = new Mat();
CvInvoke.ExtractChannel(img, channel, i);
channels[i] = channel;
}
}
else
{
throw new ArgumentException(String.Format("The input image type of {0} is not supported", image.GetType().ToString()));
}
Type[] genericArguments = imageType.GetGenericArguments();
String[] channelNames;
Color[] colors;
Type typeOfDepth;
if (genericArguments.Length > 0)
{
IColor typeOfColor = Activator.CreateInstance(genericArguments[0]) as IColor;
channelNames = Reflection.ReflectColorType.GetNamesOfChannels(typeOfColor);
colors = Reflection.ReflectColorType.GetDisplayColorOfChannels(typeOfColor);
typeOfDepth = imageType.GetGenericArguments()[1];
}
else
{
channelNames = new String[image.NumberOfChannels];
colors = new Color[image.NumberOfChannels];
for (int i = 0; i < image.NumberOfChannels; i++)
{
channelNames[i] = String.Format("Channel {0}", i);
colors[i] = Color.Red;
}
if (image is Mat)
{
typeOfDepth = CvInvoke.GetDepthType(((Mat)image).Depth);
} else if (image is UMat)
{
typeOfDepth = CvInvoke.GetDepthType(((UMat)image).Depth);
}
else
{
throw new ArgumentException(String.Format("Unable to get the type of depth from image of type {0}", image.GetType().ToString()));
}
}
float minVal, maxVal;
#region Get the maximum and minimum color intensity values
if (typeOfDepth == typeof(Byte))
{
minVal = 0.0f;
maxVal = 256.0f;
}
else
{
#region obtain the maximum and minimum color value
double[] minValues, maxValues;
Point[] minLocations, maxLocations;
image.MinMax(out minValues, out maxValues, out minLocations, out maxLocations);
double min = minValues[0], max = maxValues[0];
for (int i = 1; i < minValues.Length; i++)
{
if (minValues[i] < min) min = minValues[i];
if (maxValues[i] > max) max = maxValues[i];
}
#endregion
minVal = (float)min;
maxVal = (float)max;
}
#endregion
for (int i = 0; i < channels.Length; i++)
{
//using (DenseHistogram hist = new DenseHistogram(numberOfBins, new RangeF(minVal, maxVal)))
using (Mat hist = new Mat())
using (Util.VectorOfMat vm = new Util.VectorOfMat())
{
vm.Push(channels[i]);
float[] ranges = new float[] { minVal, maxVal };
CvInvoke.CalcHist(vm, new int[] { 0 }, null, hist, new int[] { numberOfBins }, ranges, false);
//hist.Calculate(new IImage[1] { channels[i] }, true, null);
AddHistogram(channelNames[i], colors[i], hist, numberOfBins, ranges );
}
}
}
/// <summary>
/// Remove all the histogram from the control. You should call the Refresh() function to update the control after all modification is complete.
/// </summary>
public void ClearHistogram()
{
zedGraphControl1.MasterPane.PaneList.Clear();
}
/// <summary>
/// Paint the histogram
/// </summary>
public new void Refresh()
{
zedGraphControl1.MasterPane.AxisChange(_graphic);
zedGraphControl1.MasterPane.SetLayout(_graphic, PaneLayout.SingleColumn);
base.Refresh();
}
}
}