using System; using System.Drawing; using System.Drawing.Drawing2D; using System.Windows.Forms; using OpenCvSharp; namespace PaintDotNet.CustomControl { public partial class HistogramControl : UserControl { /// /// panel画板 /// private PanelEx panelEx1; /// /// 控件的宽 /// private int width; /// /// 控件的高 /// private int height; /// /// 区间1的起止值 /// private int start = 0, end = 0; /// /// 区间2的起止值 /// private int start1 = 0, end1 = 0; /// /// 画笔 /// private Pen pen = new Pen(Color.Red); /// /// 直方图的bitmap /// private Bitmap bitmap; /// /// 1个区间/2个区间 /// private int flag = 1; /// /// 鼠标按下标志 /// private bool press = false; /// /// 标记鼠标按下的时候在那根线上 1、2、3、4 /// private int x = 0; /// /// 中间的 /// private GraphicsPath path1, path2; public int Flag { get { return flag; } set { this.flag = value; this.panelEx1.Refresh(); } } /// /// 公开的事件,第一条线拖拽的事件 /// public event EventHandler> DragOneEventActionFinish; private void OnDragOneEventActionFinish(int start) { if (DragOneEventActionFinish != null) { DragOneEventActionFinish(this, new EventArgs(start)); } } public event EventHandler> DragTwoEventActionFinish; private void OnDragTwoEventActionFinish(int end) { if (DragTwoEventActionFinish != null) { DragTwoEventActionFinish(this, new EventArgs(end)); } } public event EventHandler> DragThreeEventActionFinish; private void OnDragThreeEventActionFinish(int start1) { if (DragThreeEventActionFinish != null) { DragThreeEventActionFinish(this, new EventArgs(start1)); } } public event EventHandler> DragFourEventActionFinish; private void OnDragFourEventActionFinish(int start1) { if (DragFourEventActionFinish != null) { DragFourEventActionFinish(this, new EventArgs(start1)); } } public event EventHandler> DragFiveEventActionFinish; private void OnDragFiveEventActionFinish(int[] startend) { if (DragFiveEventActionFinish != null) { DragFiveEventActionFinish(this, new EventArgs(startend)); } } public event EventHandler> DragSixEventActionFinish; private void OnDragSixEventActionFinish(int[] start1end1) { if (DragSixEventActionFinish != null) { DragSixEventActionFinish(this, new EventArgs(start1end1)); } } public HistogramControl() { InitializeComponent(); this.panelEx1.Paint += new PaintEventHandler(this.panelEx_Paint); this.panelEx1.MouseDown += new MouseEventHandler(this.panelEx_MouseDown); this.panelEx1.MouseMove += new MouseEventHandler(this.panelEx_MouseMove); this.panelEx1.MouseUp += new MouseEventHandler(this.panelEx_MouseUp); } int oldx = 0; /// /// 鼠标按下事件,判断是否点在了线上 /// /// /// private void panelEx_MouseDown(object sender, MouseEventArgs e) { if (e.Button == MouseButtons.Left) { if (flag == 1 || flag == 2) { if ((e.X > start-5 && e.X < start + 5) || (e.X > end-5 && e.X < end + 5)) { x = (e.X > end - 5 && e.X < end + 5) ? 2 : 1; press = true; } if(new Region(path1).IsVisible(e.X, e.Y)) { x = 5; oldx = e.X; press = true; } } if (flag == 2) { if ((e.X > start1 - 5 && e.X < start1 + 5) || (e.X > end1 - 5 && e.X < end1 + 5)) { x = (e.X > end1 - 5 && e.X < end1 + 5) ? 4 : 3; press = true; } if (new Region(path2).IsVisible(e.X, e.Y)) { x = 6; oldx = e.X; press = true; } } } } /// /// 鼠标移动事件 /// /// /// private void panelEx_MouseMove(object sender, MouseEventArgs e) { if((e.X > start - 5 && e.X < start + 5) || (e.X > end - 5 && e.X < end + 5) || (e.X > start1 - 5 && e.X < start1 + 5) || (e.X > end1 - 5 && e.X < end1 + 5)) { this.Cursor = Cursors.VSplit; } else { if ((path1!=null && new Region(path1).IsVisible(e.X, e.Y))) { this.Cursor = Cursors.Hand; } else if ((path2 != null && new Region(path2).IsVisible(e.X, e.Y))) { this.Cursor = Cursors.Hand; } else if (press) { this.Cursor = Cursors.VSplit; } else { this.Cursor = Cursors.Default; } } if(e.Button == MouseButtons.Left && press && e.X>=0 && e.X<=width) { switch(x) { case 1: this.start = e.X; if (this.start > this.end) this.start = this.end; break; case 2: this.end = e.X; if (this.end < this.start) this.end = this.start; break; case 3: this.start1 = e.X; if (this.start1 > this.end1) this.start1 = this.end1; break; case 4: this.end1 = e.X; if (this.end1 < this.start1) this.end1 = this.start1; break; case 5: this.start += -oldx + e.X; this.end += -oldx + e.X; if (this.start < 0) this.start = 0; if (this.end > width) this.end = width; break; case 6: this.start1 += -oldx + e.X; this.end1 += -oldx + e.X; if (this.start1 < 0) this.start1 = 0; if (this.end1 > width) this.end1 = width; break; } oldx = e.X; this.panelEx1.Refresh(); } } /// /// 鼠标抬起事件 /// /// /// private void panelEx_MouseUp(object sender, MouseEventArgs e) { if (this.press) { switch(this.x) { case 1: OnDragOneEventActionFinish(Convert.ToInt32(this.start * 1f * 255 / width)); break; case 2: OnDragTwoEventActionFinish(Convert.ToInt32(this.end * 1f * 255 / width)); break; case 3: OnDragThreeEventActionFinish(Convert.ToInt32(this.start1 * 1f * 255 / width)); break; case 4: OnDragFourEventActionFinish(Convert.ToInt32(this.end1 * 1f * 255 / width)); break; case 5: OnDragFiveEventActionFinish(new int[] { Convert.ToInt32(this.end * 1f * 255 / width), Convert.ToInt32(this.start * 1f * 255 / width) }); //OnDragTwoEventActionFinish(Convert.ToInt32(this.end * 1f * 255 / width)); //OnDragOneEventActionFinish(Convert.ToInt32(this.start * 1f * 255 / width)); break; case 6: OnDragSixEventActionFinish(new int[] { Convert.ToInt32(this.end1 * 1f * 255 / width), Convert.ToInt32(this.start1 * 1f * 255 / width) }); //OnDragFourEventActionFinish(Convert.ToInt32(this.end1 * 1f * 255 / width)); //OnDragThreeEventActionFinish(Convert.ToInt32(this.start1 * 1f * 255 / width)); break; } } this.press = false; this.x = 0; } /// /// 绘制事件 /// /// /// private void panelEx_Paint(object sender, PaintEventArgs e) { if (bitmap != null) { e.Graphics.DrawImage(bitmap, 0, 0, width, height); } if(flag==1 || flag==2) { e.Graphics.DrawLine(pen, new PointF(start, 0), new PointF(start, height)); e.Graphics.DrawLine(pen, new PointF(end, 0), new PointF(end, height)); DrawHandle(start, end, e.Graphics, 1); } if (flag == 2) { e.Graphics.DrawLine(pen, new PointF(start1, 0), new PointF(start1, height)); e.Graphics.DrawLine(pen, new PointF(end1, 0), new PointF(end1, height)); DrawHandle(start1, end1, e.Graphics, 2); } } public void UpdateVerticalBarWithOneScope(int start, int end) { this.flag = 1; this.start = Convert.ToInt32(start * width * 1f / 255); this.end = Convert.ToInt32(end * width * 1f / 255); this.panelEx1.Refresh(); } public void UpdateVerticalBarWithTwoScope(int start, int end, int start1, int end1) { this.flag = 2; this.start = Convert.ToInt32(start * width * 1f / 255); this.end = Convert.ToInt32(end * width * 1f / 255); this.start1 = Convert.ToInt32(start1 * width * 1f / 255); this.end1 = Convert.ToInt32(end1 * width * 1f / 255); this.panelEx1.Refresh(); } private void InitializeComponent() { this.panelEx1 = new PaintDotNet.PanelEx(); this.SuspendLayout(); // // panelEx1 // this.panelEx1.BackColor = System.Drawing.SystemColors.ActiveBorder; this.panelEx1.Dock = System.Windows.Forms.DockStyle.Fill; this.panelEx1.HideHScroll = false; this.panelEx1.HideVScroll = false; this.panelEx1.IgnoreSetFocus = false; this.panelEx1.Location = new System.Drawing.Point(0, 0); this.panelEx1.Margin = new System.Windows.Forms.Padding(0); this.panelEx1.Name = "panelEx1"; this.panelEx1.ScrollPosition = new System.Drawing.Point(0, 0); this.panelEx1.Size = new System.Drawing.Size(255, 150); this.panelEx1.TabIndex = 0; // // HistogramControl // this.Controls.Add(this.panelEx1); this.Name = "HistogramControl"; this.Size = new System.Drawing.Size(255, 150); this.ResumeLayout(false); } /// /// 绘制直方图 /// /// imageMat /// 是否绘制单通道灰度图 /// 需要绘制的直方图宽度 /// 需要绘制的直方图高度 /// isGray为false的时候生效,绘制RGB三通道的直方图的时候,0全部绘制,1B,2G,3R public void CreateHistogram(OpenCvSharp.Mat imageMat, bool isGray, int width, int height, int channel) { this.width = width; this.height = height; //Mat mat = OpenCvSharp.Extensions.BitmapConverter.ToMat(bitmap); if (isGray) { this.DrawGrayHistogram(imageMat.CvtColor(ColorConversionCodes.BGRA2GRAY)); } else { this.DrawRGBHistogram(imageMat.Clone(), channel); } } private void DrawGrayHistogram(Mat mat) { //配置输出的结果存储的 空间 ,用MatND类型来存储结果 Mat hist = new Mat(); //设置计算直方图的维度 int dims = 1; //直方图的每一个维度的柱条的数目(就是将数值分组,共有多少组) int[] histSize = { 255 }; Rangef[] pranges = new Rangef[1];//一个通道,范围 pranges[0] = new Rangef(0.0F, 256.0F); //6--计算直方图 Cv2.CalcHist(new Mat[1] { mat }, new int[] { 0 }, new Mat(), hist, dims, histSize, pranges); int hist_w = width; int hist_h = height; int nHistSize = 256; double bin_w = (double)hist_w / nHistSize; //区间 Mat histImage = new Mat(hist_h, hist_w, MatType.CV_8UC3, Scalar.All(255));//创建一个黑底的图像,为了可以显示彩色,所以该绘制图像是一个8位的3通道图像 Cv2.Normalize(hist, hist, 0, histImage.Rows-10, NormTypes.MinMax, -1, new Mat()); this.bitmap = OpenCvSharp.Extensions.BitmapConverter.ToBitmap(histImage); Graphics graphics = Graphics.FromImage(this.bitmap); //在直方图画布上画出直方图 for (int i = 1; i < nHistSize-1; i++) { System.Drawing.PointF point1 = new System.Drawing.PointF((float)(bin_w * (i - 1)), (float)(hist_h - 5 - Math.Round(hist.At(i - 1)))); System.Drawing.PointF point2 = new System.Drawing.PointF((float)(bin_w * (i)), (float)(hist_h - 2 - Math.Round(hist.At(i)))); graphics.SmoothingMode = SmoothingMode.AntiAlias; graphics.DrawLine(new Pen(Color.FromArgb(100, 100, 100)), point1, point2); //Cv2.Line(histImage, point1, point2, new Scalar(100, 100, 100), 1, LineTypes.AntiAlias, 0); /*OpenCvSharp.Point point1 = new OpenCvSharp.Point(bin_w * (i - 1), hist_h - 5 - Math.Round(hist.At(i - 1))); OpenCvSharp.Point point2 = new OpenCvSharp.Point(bin_w * (i), hist_h - 2 - Math.Round(hist.At(i))); Cv2.Line(histImage, point1, point2, new Scalar(100, 100, 100), 1, LineTypes.AntiAlias, 0);*/ } //this.bitmap = OpenCvSharp.Extensions.BitmapConverter.ToBitmap(histImage); this.panelEx1.Refresh(); } private void DrawRGBHistogram(Mat mat, int channel) { Mat[] src = mat.Split(); //配置输出的结果存储的 空间 ,用MatND类型来存储结果 Mat[] hists = new Mat[] { new Mat(), new Mat(), new Mat() }; //设置计算直方图的维度 int dims = 1; //直方图的每一个维度的柱条的数目(就是将数值分组,共有多少组) int[] histSize = { 255 }; Rangef[] pranges = new Rangef[1];//一个通道,范围 pranges[0] = new Rangef(0.0F, 256.0F); //6--计算直方图 Cv2.CalcHist(new Mat[] { src[0] }, new int[] { 0 }, new Mat(), hists[0], dims, histSize, pranges); Cv2.CalcHist(new Mat[] { src[1] }, new int[] { 0 }, new Mat(), hists[1], dims, histSize, pranges); Cv2.CalcHist(new Mat[] { src[2] }, new int[] { 0 }, new Mat(), hists[2], dims, histSize, pranges); int hist_w = width; int hist_h = height; int nHistSize = 256; double bin_w = (double)hist_w / nHistSize; //区间 Mat histImage = new Mat(hist_h, hist_w, MatType.CV_8UC3, Scalar.All(255));//创建一个黑底的图像,为了可以显示彩色,所以该绘制图像是一个8位的3通道图像 Cv2.Normalize(hists[0], hists[0], 0, histImage.Rows - 10, NormTypes.MinMax, -1, new Mat()); Cv2.Normalize(hists[1], hists[1], 0, histImage.Rows - 10, NormTypes.MinMax, -1, new Mat()); Cv2.Normalize(hists[2], hists[2], 0, histImage.Rows - 10, NormTypes.MinMax, -1, new Mat()); //在直方图画布上画出直方图 for (int i = 1; i < nHistSize-1; i++) { if(channel == 0 || channel == 3) Cv2.Line(histImage, new OpenCvSharp.Point(bin_w * (i - 1), hist_h - 5 - Math.Round(hists[0].At(i - 1))), new OpenCvSharp.Point(bin_w * (i), hist_h - 5 - Math.Round(hists[0].At(i))), new Scalar(255, 0, 0), 1, LineTypes.AntiAlias, 0); if(channel == 0 || channel == 2) Cv2.Line(histImage, new OpenCvSharp.Point(bin_w * (i - 1), hist_h - 5 - Math.Round(hists[1].At(i - 1))), new OpenCvSharp.Point(bin_w * (i), hist_h - 5 - Math.Round(hists[1].At(i))), new Scalar(0, 255, 0), 1, LineTypes.AntiAlias, 0); if(channel == 0 || channel == 1) Cv2.Line(histImage, new OpenCvSharp.Point(bin_w * (i - 1), hist_h - 5 - Math.Round(hists[2].At(i - 1))), new OpenCvSharp.Point(bin_w * (i), hist_h - 5 - Math.Round(hists[2].At(i))), new Scalar(0, 0, 255), 1, LineTypes.AntiAlias, 0); } this.bitmap = OpenCvSharp.Extensions.BitmapConverter.ToBitmap(histImage); this.panelEx1.Refresh(); } /// /// 绘制直线间的形状 /// /// x轴起点 /// x轴终点 /// Graphics private void DrawHandle(int s, int e, Graphics g, int type) { float v4 = height / 4; float h4 = (e - s) / 4; float h2 = (e - s) / 2; { PointF p1 = new PointF(s + h4, height / 2); PointF p2 = new PointF(s + (h4 * 3), height / 2); PointF p3 = new PointF(s + h2, v4); PointF p4 = new PointF(s + h2, v4 * 3); g.DrawLine(pen, new PointF(s, height / 2), p1); g.DrawLine(pen, p2, new PointF(e, height / 2)); PointF[] points = new PointF[4]; points[0] = p1; points[1] = p3; points[2] = p2; points[3] = p4; g.DrawLine(pen, p1, p3); g.DrawLine(pen, p2, p3); g.DrawLine(pen, p1, p4); g.DrawLine(pen, p2, p4); if(type==1) { path1 = new GraphicsPath(); path1.AddPolygon(points); } else if(type == 2) { path2 = new GraphicsPath(); path2.AddPolygon(points); } } } } }