using System; using System.Collections.Generic; using System.ComponentModel; using System.Drawing; using System.Data; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Windows.Forms; using PaintDotNet.Base.SettingModel; using OpenCvSharp; using PaintDotNet.CustomControl; using PaintDotNet.Camera; using OpenCvSharp.Extensions; using System.Threading; namespace PaintDotNet.Preview2 { public class DisplayControl : UserControl { #region 初始化变量 private AppWorkspace AppWorkspace; /// /// 一个矩阵数组,用来接收直方图,记得全部初始化 /// Mat[] oldHists = new Mat[] { new Mat(), new Mat(), new Mat() }; /// /// 相机采集的图像 /// Mat OldMat; /// /// 灰度图 /// private bool isGray = true; /// /// BGR线条颜色 /// private Scalar[] color = new Scalar[] { new Scalar(255, 0, 0, 255), new Scalar(0, 255, 0, 255), new Scalar(0, 0, 255, 255) }; #endregion #region 控件 private Label label0005; /// /// 相机参数的Model /// private CameraParamModel m_cameraParamModel; private ICamera m_camera => CameraManager.CurrentCamera; private Label label7; private TriangleTrackBar trackBar3; private Label label6; private TriangleTrackBar trackBar2; private Label label5; private TriangleTrackBar trackBar1; private Label label3; private Label label2; private Label label1; public Button button5; public Button button4; private UCTrackBar ucTrackBar1; private SelectButton logButton; private SelectButton skipButton; private PictureBox pictureBox1; private GroupBox groupBox1; private Panel panel1; private Panel panel2; private TableLayoutPanel tableLayoutPanel1; private System.Threading.Timer m_aeTimer; #endregion public DisplayControl() { InitializeComponent(); InitializeLanguageText(); try { InitializeControlData(); } catch { } } /// /// 设置直方图的图像 /// /// /// /// 设置下拉等数据源 /// private void InitializeControlData() { m_cameraParamModel = Startup.instance.cameraParamModel; if (m_camera.IsOpen()) { m_aeTimer = new System.Threading.Timer(TimerUpdateHist, null, 500, 500); } ucTrackBar1.Value1 = m_camera.LeftLevel; ucTrackBar1.Value2 = (int)m_camera.Gamma; ucTrackBar1.Value3 = m_camera.RightLevel; trackBar1.Value = m_cameraParamModel.parame.Light; label5.Text = trackBar1.Value + ""; trackBar2.Value = m_cameraParamModel.parame.Contrast; label6.Text = trackBar2.Value + ""; trackBar3.Value = m_cameraParamModel.parame.Gamma; label7.Text = trackBar3.Value / 100f + ""; } private void InitializeLanguageText() { this.label0005.Text = PdnResources.GetString("Menu.timeofexposure.text") + ":"; this.label3.Text = PdnResources.GetString("Menu.Gammavalue.text") + ":"; this.label2.Text = PdnResources.GetString("Menu.Contrast.text") + ":"; this.label1.Text = PdnResources.GetString("Menu.luminance.text") + ":"; this.button5.Text = PdnResources.GetString("Menu.Originalstate.text"); this.button4.Text = PdnResources.GetString("Menu.Gammavalue.text") + "1.00"; this.groupBox1.Text = PdnResources.GetString("Menu.Tools.Histogram.Text"); } private void InitializeComponent() { this.label0005 = new System.Windows.Forms.Label(); this.label7 = new System.Windows.Forms.Label(); this.trackBar3 = new PaintDotNet.CustomControl.TriangleTrackBar(); this.label6 = new System.Windows.Forms.Label(); this.trackBar2 = new PaintDotNet.CustomControl.TriangleTrackBar(); this.label5 = new System.Windows.Forms.Label(); this.trackBar1 = new PaintDotNet.CustomControl.TriangleTrackBar(); this.label3 = new System.Windows.Forms.Label(); this.label2 = new System.Windows.Forms.Label(); this.label1 = new System.Windows.Forms.Label(); this.button5 = new System.Windows.Forms.Button(); this.button4 = new System.Windows.Forms.Button(); this.ucTrackBar1 = new PaintDotNet.CustomControl.UCTrackBar(); this.logButton = new PaintDotNet.CustomControl.SelectButton(); this.skipButton = new PaintDotNet.CustomControl.SelectButton(); this.pictureBox1 = new System.Windows.Forms.PictureBox(); this.groupBox1 = new System.Windows.Forms.GroupBox(); this.tableLayoutPanel1 = new System.Windows.Forms.TableLayoutPanel(); this.panel2 = new System.Windows.Forms.Panel(); this.panel1 = new System.Windows.Forms.Panel(); ((System.ComponentModel.ISupportInitialize)(this.pictureBox1)).BeginInit(); this.groupBox1.SuspendLayout(); this.tableLayoutPanel1.SuspendLayout(); this.panel2.SuspendLayout(); this.panel1.SuspendLayout(); this.SuspendLayout(); // // label0005 // this.label0005.AutoSize = true; this.label0005.Location = new System.Drawing.Point(24, 39); this.label0005.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0); this.label0005.Name = "label0005"; this.label0005.Size = new System.Drawing.Size(82, 15); this.label0005.TabIndex = 12; this.label0005.Text = "曝光时间:"; // // label7 // this.label7.AutoSize = true; this.label7.Location = new System.Drawing.Point(241, 83); this.label7.Margin = new System.Windows.Forms.Padding(0, 11, 0, 0); this.label7.Name = "label7"; this.label7.Size = new System.Drawing.Size(29, 12); this.label7.TabIndex = 59; this.label7.Text = "1.00"; // // trackBar3 // this.trackBar3.Dock = System.Windows.Forms.DockStyle.Top; this.trackBar3.Location = new System.Drawing.Point(61, 75); this.trackBar3.Maximum = 255; this.trackBar3.Minimum = 64; this.trackBar3.Name = "trackBar3"; this.trackBar3.Size = new System.Drawing.Size(177, 28); this.trackBar3.TabIndex = 58; this.trackBar3.Value = 100; this.trackBar3.TrackBarScroll += new System.EventHandler(this.trackBar3_Scroll); // // label6 // this.label6.AutoSize = true; this.label6.Location = new System.Drawing.Point(241, 49); this.label6.Margin = new System.Windows.Forms.Padding(0, 11, 0, 0); this.label6.Name = "label6"; this.label6.Size = new System.Drawing.Size(29, 12); this.label6.TabIndex = 57; this.label6.Text = "1.00"; // // trackBar2 // this.trackBar2.Dock = System.Windows.Forms.DockStyle.Top; this.trackBar2.Location = new System.Drawing.Point(61, 41); this.trackBar2.Maximum = 63; this.trackBar2.Minimum = 0; this.trackBar2.Name = "trackBar2"; this.trackBar2.Size = new System.Drawing.Size(177, 28); this.trackBar2.TabIndex = 56; this.trackBar2.Value = 63; this.trackBar2.TrackBarScroll += new System.EventHandler(this.trackBar2_Scroll); // // label5 // this.label5.AutoSize = true; this.label5.Location = new System.Drawing.Point(241, 15); this.label5.Margin = new System.Windows.Forms.Padding(0, 11, 0, 0); this.label5.Name = "label5"; this.label5.Size = new System.Drawing.Size(29, 12); this.label5.TabIndex = 55; this.label5.Text = "-0.5"; // // trackBar1 // this.trackBar1.Dock = System.Windows.Forms.DockStyle.Top; this.trackBar1.Location = new System.Drawing.Point(61, 7); this.trackBar1.Maximum = 255; this.trackBar1.Minimum = 0; this.trackBar1.Name = "trackBar1"; this.trackBar1.Size = new System.Drawing.Size(177, 28); this.trackBar1.TabIndex = 54; this.trackBar1.Value = 0; this.trackBar1.TrackBarScroll += new System.EventHandler(this.Light_Scroll); // // label3 // this.label3.AutoSize = true; this.label3.Location = new System.Drawing.Point(4, 83); this.label3.Margin = new System.Windows.Forms.Padding(0, 11, 0, 0); this.label3.Name = "label3"; this.label3.Size = new System.Drawing.Size(53, 12); this.label3.TabIndex = 51; this.label3.Text = "伽马值:"; // // label2 // this.label2.AutoSize = true; this.label2.Location = new System.Drawing.Point(4, 49); this.label2.Margin = new System.Windows.Forms.Padding(0, 11, 0, 0); this.label2.Name = "label2"; this.label2.Size = new System.Drawing.Size(53, 12); this.label2.TabIndex = 50; this.label2.Text = "对比度:"; // // label1 // this.label1.AutoSize = true; this.label1.Location = new System.Drawing.Point(4, 15); this.label1.Margin = new System.Windows.Forms.Padding(0, 11, 0, 0); this.label1.Name = "label1"; this.label1.Size = new System.Drawing.Size(41, 12); this.label1.TabIndex = 49; this.label1.Text = "亮度:"; // // button5 // this.button5.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left))); this.button5.Location = new System.Drawing.Point(87, 288); this.button5.Name = "button5"; this.button5.Size = new System.Drawing.Size(75, 23); this.button5.TabIndex = 48; this.button5.Text = "原始状态"; this.button5.UseVisualStyleBackColor = true; this.button5.Click += new System.EventHandler(this.button5_Click); // // button4 // this.button4.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left))); this.button4.Location = new System.Drawing.Point(9, 288); this.button4.Name = "button4"; this.button4.Size = new System.Drawing.Size(75, 23); this.button4.TabIndex = 47; this.button4.Text = "伽马值1.00"; this.button4.UseVisualStyleBackColor = true; this.button4.Click += new System.EventHandler(this.button4_Click); // // ucTrackBar1 // this.ucTrackBar1.DcimalDigits = 0; this.ucTrackBar1.Dock = System.Windows.Forms.DockStyle.Top; this.ucTrackBar1.LineColor = System.Drawing.Color.FromArgb(((int)(((byte)(255)))), ((int)(((byte)(77)))), ((int)(((byte)(59))))); this.ucTrackBar1.LineWidth = 8F; this.ucTrackBar1.Location = new System.Drawing.Point(3, 131); this.ucTrackBar1.MaxValue = 255F; this.ucTrackBar1.MinValue = 0F; this.ucTrackBar1.Name = "ucTrackBar1"; this.ucTrackBar1.Size = new System.Drawing.Size(282, 15); this.ucTrackBar1.TabIndex = 44; this.ucTrackBar1.Text = "ucTrackBar1"; this.ucTrackBar1.Value1 = 0F; this.ucTrackBar1.Value2 = 127F; this.ucTrackBar1.Value3 = 255F; this.ucTrackBar1.Value1Changed += new System.EventHandler(this.LeftLevelChanged); this.ucTrackBar1.Value2Changed += new System.EventHandler(this.ucTrackBar1_Value2Changed); this.ucTrackBar1.Value3Changed += new System.EventHandler(this.RightLevelChanged); // // logButton // this.logButton.BackColor = System.Drawing.SystemColors.ControlDark; this.logButton.BtnSelect = false; this.logButton.BtnText = "log"; this.logButton.Location = new System.Drawing.Point(69, 1); this.logButton.Name = "logButton"; this.logButton.Size = new System.Drawing.Size(41, 21); this.logButton.TabIndex = 43; this.logButton.Click += new System.EventHandler(this.logButton_Click); // // skipButton // this.skipButton.BackColor = System.Drawing.SystemColors.ControlDark; this.skipButton.BtnSelect = false; this.skipButton.BtnText = "skip"; this.skipButton.Location = new System.Drawing.Point(166, 0); this.skipButton.Name = "skipButton"; this.skipButton.Size = new System.Drawing.Size(41, 21); this.skipButton.TabIndex = 42; this.skipButton.Click += new System.EventHandler(this.skipButton_Click); // // pictureBox1 // this.pictureBox1.BackColor = System.Drawing.Color.White; this.pictureBox1.BackgroundImageLayout = System.Windows.Forms.ImageLayout.Stretch; this.pictureBox1.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle; this.pictureBox1.Dock = System.Windows.Forms.DockStyle.Fill; this.pictureBox1.Location = new System.Drawing.Point(7, 0); this.pictureBox1.Name = "pictureBox1"; this.pictureBox1.Size = new System.Drawing.Size(268, 114); this.pictureBox1.SizeMode = System.Windows.Forms.PictureBoxSizeMode.StretchImage; this.pictureBox1.TabIndex = 41; this.pictureBox1.TabStop = false; // // groupBox1 // this.groupBox1.Controls.Add(this.tableLayoutPanel1); this.groupBox1.Controls.Add(this.panel2); this.groupBox1.Controls.Add(this.button5); this.groupBox1.Controls.Add(this.button4); this.groupBox1.Controls.Add(this.ucTrackBar1); this.groupBox1.Controls.Add(this.panel1); this.groupBox1.Dock = System.Windows.Forms.DockStyle.Fill; this.groupBox1.Location = new System.Drawing.Point(0, 6); this.groupBox1.Name = "groupBox1"; this.groupBox1.Size = new System.Drawing.Size(288, 322); this.groupBox1.TabIndex = 60; this.groupBox1.TabStop = false; this.groupBox1.Text = "直方图"; // // tableLayoutPanel1 // this.tableLayoutPanel1.ColumnCount = 3; this.tableLayoutPanel1.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Absolute, 54F)); this.tableLayoutPanel1.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 100F)); this.tableLayoutPanel1.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Absolute, 37F)); this.tableLayoutPanel1.Controls.Add(this.label1, 0, 0); this.tableLayoutPanel1.Controls.Add(this.label2, 0, 1); this.tableLayoutPanel1.Controls.Add(this.label3, 0, 2); this.tableLayoutPanel1.Controls.Add(this.label5, 2, 0); this.tableLayoutPanel1.Controls.Add(this.label6, 2, 1); this.tableLayoutPanel1.Controls.Add(this.label7, 2, 2); this.tableLayoutPanel1.Controls.Add(this.trackBar1, 1, 0); this.tableLayoutPanel1.Controls.Add(this.trackBar2, 1, 1); this.tableLayoutPanel1.Controls.Add(this.trackBar3, 1, 2); this.tableLayoutPanel1.Dock = System.Windows.Forms.DockStyle.Top; this.tableLayoutPanel1.Location = new System.Drawing.Point(3, 168); this.tableLayoutPanel1.Name = "tableLayoutPanel1"; this.tableLayoutPanel1.Padding = new System.Windows.Forms.Padding(4); this.tableLayoutPanel1.RowCount = 3; this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 33.33333F)); this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 33.33333F)); this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 33.33333F)); this.tableLayoutPanel1.Size = new System.Drawing.Size(282, 110); this.tableLayoutPanel1.TabIndex = 61; // // panel2 // this.panel2.Controls.Add(this.logButton); this.panel2.Controls.Add(this.skipButton); this.panel2.Dock = System.Windows.Forms.DockStyle.Top; this.panel2.Location = new System.Drawing.Point(3, 146); this.panel2.Name = "panel2"; this.panel2.Size = new System.Drawing.Size(282, 22); this.panel2.TabIndex = 60; // // panel1 // this.panel1.Controls.Add(this.pictureBox1); this.panel1.Dock = System.Windows.Forms.DockStyle.Top; this.panel1.Location = new System.Drawing.Point(3, 17); this.panel1.Name = "panel1"; this.panel1.Padding = new System.Windows.Forms.Padding(7, 0, 7, 0); this.panel1.Size = new System.Drawing.Size(282, 114); this.panel1.TabIndex = 0; // // DisplayControl // this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 12F); this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; this.Controls.Add(this.groupBox1); this.Name = "DisplayControl"; this.Padding = new System.Windows.Forms.Padding(0, 6, 0, 0); this.Size = new System.Drawing.Size(288, 328); ((System.ComponentModel.ISupportInitialize)(this.pictureBox1)).EndInit(); this.groupBox1.ResumeLayout(false); this.tableLayoutPanel1.ResumeLayout(false); this.tableLayoutPanel1.PerformLayout(); this.panel2.ResumeLayout(false); this.panel1.ResumeLayout(false); this.ResumeLayout(false); } /// /// 刷新直方图 /// /// public void TimerUpdateHist(object e) { try { if (this.Parent == null) { m_aeTimer.Dispose(); return; } if (!this.Visible) return; CameraManager.Shoot((bitmap) => { try { if (bitmap == null) return; var mat = PaintDotNet.Camera.Tools.ToMat(bitmap); updateHistImg(mat); updateHistogramRect(false); } catch { } }); } catch { m_aeTimer.Dispose(); } } public unsafe void updateHistImg(OpenCvSharp.Mat mat) { OldMat = mat; isGray = true; if (this.OldMat == null) return; Mat[] mats = Cv2.Split(this.OldMat);//一张图片,将panda拆分成3个图片装进mat Mat[] mats0 = new Mat[] { mats[0] };//B Mat[] mats1; Mat[] mats2; if (mats.Length > 1) { isGray = false; mats1 = new Mat[] { mats[1] };//G mats2 = new Mat[] { mats[2] };//R } else { mats1 = new Mat[] { mats[0] };//G mats2 = new Mat[] { mats[0] };//R } int[] channels0 = new int[] { 0 };//一个通道,初始化为通道0,这些东西可以共用设置一个就行 int[] channels1 = new int[] { 0 }; int[] channels2 = new int[] { 0 }; int[] histsize = new int[] { 256 };//一个通道,初始化为256箱子 Rangef[] range = new Rangef[1];//一个通道,范围 range[0] = new Rangef(0.0F, 256.0F); //range[0].Start = 0.0F;//从0开始(含) //range[0].End = 256.0F;//到256结束(不含) Mat mask = new Mat();//不做掩码 Cv2.CalcHist(mats0, channels0, mask, oldHists[0], 1, histsize, range);//对被拆分的图片单独进行计算 Cv2.CalcHist(mats1, channels1, mask, oldHists[1], 1, histsize, range);//对被拆分的图片单独进行计算 Cv2.CalcHist(mats2, channels2, mask, oldHists[2], 1, histsize, range);//对被拆分的图片单独进行计算 var hists = oldHists; if (logButton.BtnSelect) { //取对数 for (int j = 0; j < hists.Length; j++) { List ProbPixel = new List(); for (int i = 0; i < hists[j].Rows; i++) { if (((float*)hists[j].Ptr(0))[i] == 0) { ((float*)hists[j].Ptr(0))[i] = ((float*)hists[j].Ptr(0))[i]; ProbPixel.Add(0); } else { ((float*)hists[j].Ptr(0))[i] = (float)Math.Log10(((float*)hists[j].Ptr(0))[i]/* + 9*/); ProbPixel.Add(1); } } double max1jVal = 0; double min1jVal = 0; //找到直方图中的最大值和最小值 Cv2.MinMaxLoc(hists[j], out min1jVal, out max1jVal); if (min1jVal >= max1jVal) { continue; } //归一化到0~255,并根据AxioVision添加偏置值 for (int i = 0; i < hists[j].Rows; i++) { ((float*)hists[j].Ptr(0))[i] = (float)((((float*)hists[j].Ptr(0))[i] - 0) * 255.0 / (max1jVal - 0)) + (float)(min1jVal > 0 ? (ProbPixel[i] * min1jVal * 255.0 / max1jVal) : ProbPixel[i] * 5); } } } if (skipButton.BtnSelect) { //去掉黑色部分 和 白色部分 for (int j = 0; j < hists.Length; j++) { ((float*)hists[j].Ptr(0))[0] = 0; ((float*)hists[j].Ptr(0))[255] = 0; } } double max2Val = 0; double max1Val = 0; double max0Val = 0; double minVal = 0; //为了更好显示直方图细节,使用4倍尺寸绘制直方图 int histSize = hists[0].Rows * 4; Mat histImg = new Mat(histSize, histSize, MatType.CV_8UC3, new Scalar(255, 255, 255)); //找到直方图中的最大值和最小值 Cv2.MinMaxLoc(hists[2], out minVal, out max2Val); Cv2.MinMaxLoc(hists[1], out minVal, out max1Val); Cv2.MinMaxLoc(hists[0], out minVal, out max0Val); double maxVal = Math.Max(max2Val, Math.Max(max0Val, max1Val)); if (maxVal < 1) return; // 设置最大峰值为图像高度的90% double hpt = 0.9 * histSize; //灰度图的显示直方图较为简单,显示一个通道即可 if (isGray) { Mat hist = hists[0]; int lastY2 = histSize - 1; for (int h = 0; h < hists[0].Rows; h++) { int intensity = (int)(hist.At(h) * hpt / maxVal); int lastY1 = lastY2; lastY2 = histSize - intensity - 1 - (hist.At(h) > 0 ? 4 : 0); if (lastY2 < lastY1) { Cv2.Line(histImg, new OpenCvSharp.Point(h * 4, lastY1), new OpenCvSharp.Point(h * 4, Math.Min(lastY2, lastY1 - 2)), new Scalar(0, 0, 0, 255), 2, LineTypes.Link4); } else { Cv2.Line(histImg, new OpenCvSharp.Point(h * 4, lastY1), new OpenCvSharp.Point(h * 4, Math.Max(lastY2, lastY1 + 2)), new Scalar(0, 0, 0, 255), 2, LineTypes.Link4); } } } //彩度图显示BGR三个通道的直方图 else { int lineWidth = 2; for (int j = hists.Length - 1; j >= 0; j--) { Mat hist = hists[j]; int lastY2 = histSize - 1; for (int h = 0; h < hists[0].Rows; h++) { int intensity = (int)(hist.At(h) * hpt / maxVal); int lastY1 = lastY2; lastY2 = histSize - intensity - 1 - (hist.At(h) > 0 ? 4 : 0); if (h > 0) { //显示0.5位置的直方图,这样与AxioVision效果更加近似 int lasty12 = (lastY1 + lastY2) / 2; if (lasty12 < lastY1) { Cv2.Line(histImg, new OpenCvSharp.Point(h * 4 - 2, lastY1), new OpenCvSharp.Point(h * 4 - 2, Math.Min(lasty12, lastY1 - 2)), color[j], lineWidth, LineTypes.Link4); } else { Cv2.Line(histImg, new OpenCvSharp.Point(h * 4 - 2, lastY1), new OpenCvSharp.Point(h * 4 - 2, Math.Max(lasty12, lastY1 + 2)), color[j], lineWidth, LineTypes.Link4/*AntiAlias*/); } if (lastY2 < lasty12) { Cv2.Line(histImg, new OpenCvSharp.Point(h * 4, lasty12), new OpenCvSharp.Point(h * 4, Math.Min(lastY2, lasty12 - 2)), color[j], lineWidth, LineTypes.Link4); } else { Cv2.Line(histImg, new OpenCvSharp.Point(h * 4, lasty12), new OpenCvSharp.Point(h * 4, Math.Max(lastY2, lasty12 + 2)), color[j], lineWidth, LineTypes.Link4/*AntiAlias*/); } } else { //灰度值为0的线的绘制 if (lastY2 < lastY1) { Cv2.Line(histImg, new OpenCvSharp.Point(h * 4, lastY1), new OpenCvSharp.Point(h * 4, Math.Min(lastY2, lastY1 - 2)), color[j], lineWidth, LineTypes.Link4); } else { Cv2.Line(histImg, new OpenCvSharp.Point(h * 4, lastY1), new OpenCvSharp.Point(h * 4, Math.Max(lastY2, lastY1 + 2)), color[j], lineWidth, LineTypes.Link4/*AntiAlias*/); } } } } } this.pictureBox1.BackgroundImage = OpenCvSharp.Extensions.BitmapConverter.ToBitmap(histImg); } /// /// 伽马1.00 /// 需要调整直线的弧度 /// 直方图曲线根据伽马值进行变化 /// /// /// private void button4_Click(object sender, EventArgs e) { this.trackBar3.Value = 100; trackBar3_Scroll(null, null); } /// /// 原始状态 /// private void button5_Click(object sender, EventArgs e) { this.trackBar1.Value = 64; Light_Scroll(null, null); this.trackBar2.Value = 33; trackBar2_Scroll(null, null); this.trackBar3.Value = 100; trackBar3_Scroll(null, null); m_camera.LeftLevel = 0; m_camera.RightLevel = 255; ucTrackBar1.Value1 = 0; ucTrackBar1.Value3 = 255; } /// /// skip按钮 /// 显示直方图时,忽略黑色的灰度或颜色值。 /// 这使您可以为背景为黑色的图像实现有意义的直方图显示。 /// private void skipButton_Click(object sender, EventArgs e) { if (this.OldMat == null) { return; } //设置按钮的选中/非选择的状态 skipButton.BtnSelect = !skipButton.BtnSelect; } /// /// log按钮 /// 以对数比例显示直方图 /// /// /// private void logButton_Click(object sender, EventArgs e) { if (this.OldMat == null) { return; } //设置按钮的选中/非选择的状态 logButton.BtnSelect = !logButton.BtnSelect; } /// /// 亮度改变 /// /// /// private void Light_Scroll(object sender, EventArgs e) { var value = trackBar1.Value; m_camera.Light = value; label5.Text = value + ""; } /// /// 对比度改变 /// /// /// private void trackBar2_Scroll(object sender, EventArgs e) { var value = trackBar2.Value; label6.Text = value + ""; m_camera.Contrast = value; } /// /// gamma改变 /// gamma值小于1时,会拉伸图像中灰度级较低的区域,同时会压缩灰度级较高的部分 /// gamma值大于1时,会拉伸图像中灰度级较高的区域,同时会压缩灰度级较低的部分 /// /// /// private void trackBar3_Scroll(object sender, EventArgs e) { var value = trackBar3.Value; label7.Text = (value / 100.0).ToString("f2"); m_camera.Gamma = value; ucTrackBar1.Value2 = value; } /// /// 将拟合点绘制到空白图上 /// //原文链接:https://blog.csdn.net/guduruyu/article/details/72866144 /// /// 拟合点 /// 拟合矩阵的??数量 /// 空白图 /// private unsafe bool polynomial_curve_fit(OpenCvSharp.Point[] key_point, int n, Mat A) { //Number of key points int N = key_point.Length; //构造矩阵X Mat X = new Mat(n + 1, n + 1, MatType.CV_64FC1, new Scalar(0));// cv::Mat X = cv::Mat::zeros(n + 1, n + 1, CV_64FC1); for (int i = 0; i < n + 1; i++) { for (int j = 0; j < n + 1; j++) { ((double*)X.Ptr(i))[j] = 0;//111 for (int k = 0; k < N; k++) { ((double*)X.Ptr(i))[j] = X/*[i]*/.At(i, j) + (double)Math.Pow(key_point[k].X, i + j);// X.at(i, j) = X.at(i, j) + std::pow(key_point[k].x, i + j); } } } //构造矩阵Y Mat Y = new Mat(n + 1, 1, MatType.CV_64FC1, new Scalar(0));// cv::Mat Y = cv::Mat::zeros(n + 1, 1, CV_64FC1); for (int i = 0; i < n + 1; i++) { ((double*)Y.Ptr(i))[0] = 0;//111 for (int k = 0; k < N; k++) { ((double*)Y.Ptr(i))[0] = Y.At(i, 0) + (double)(Math.Pow(key_point[k].X, i) * key_point[k].Y);// Y.at(i, 0) = Y.at(i, 0) + std::pow(key_point[k].x, i) * key_point[k].y; } } //A = new Mat(n + 1, 1, MatType.CV_64FC1, new Scalar(0));// A = cv::Mat::zeros(n + 1, 1, CV_64FC1); //List dataFitted = new List(); //dataFitted.Add(Y.At(0, 0)); //dataFitted.Add(Y.At(1, 0)); //dataFitted.Add(Y.At(2, 0)); //dataFitted.Add(Y.At(3, 0)); //for (int i = 0; i < n + 1; i++) //{ // for (int j = 0; j < n + 1; j++) // { // dataFitted.Add(X.At(i, j)); // } //} //求解矩阵A Cv2.Solve(X, Y, A, DecompTypes.LU);//Cv2.Solve(X, Y, A, DecompTypes.LU); cv::solve(X, Y, A, cv::DECOMP_LU); //dataFitted.Add(A.At(0, 0)); //dataFitted.Add(A.At(1, 0)); //dataFitted.Add(A.At(2, 0)); //dataFitted.Add(A.At(3, 0)); return true; } /// /// 通过颜色通道去除像素点的千分比计算有效阈值 /// /// /// /// private OpenCvSharp.Point getStartIndex(Mat mat, float percentValue) { if (mat.Channels() == 3) { Cv2.CvtColor(mat, mat, ColorConversionCodes.RGB2GRAY); } Mat mask = new Mat();//不做掩码 Mat[] mats = Cv2.Split(mat);//一张图片,将panda拆分成3个图片装进mat Mat[] mats0 = new Mat[] { mats[0] };//B int[] channels0 = new int[] { 0 };//一个通道,初始化为通道0,这些东西可以共用设置一个就行 int[] histsize = new int[] { 256 };//一个通道,初始化为256箱子 Rangef[] range = new Rangef[1];//一个通道,范围 range[0] = new Rangef(0.0F, 256.0F); //range[0].Start = 0.0F;//从0开始(含) //range[0].End = 256.0F;//到256结束(不含) Mat hist = new Mat(); Cv2.CalcHist(mats0, channels0, mask, hist, 1, histsize, range);//对被拆分的图片单独进行计算 return this.getStartRange(hist, percentValue); } private OpenCvSharp.Point getStartRange(Mat matGray, float percentValue) { if (this.OldMat == null) { return new OpenCvSharp.Point(1, 254); ; } //计算灰度分布密度 float totalPoints = this.OldMat.Cols * this.OldMat.Rows; OpenCvSharp.Point startIndex = new OpenCvSharp.Point(0, matGray.Rows); bool foundStartTag = false; bool foundEndTag = false; //根据累计直方图分布计算左右阈值 float equalizeHists = 0; for (int i = 0; i < matGray.Rows; ++i) { equalizeHists += ((float)(matGray.At(i) / (totalPoints * 1.0))) * 1000; if (!foundStartTag && equalizeHists > percentValue) { foundStartTag = true; startIndex.X = i; } else if (equalizeHists >= 1000 - percentValue) { foundEndTag = true; startIndex.Y = i; } if (foundStartTag && foundEndTag) break; } startIndex.Y = Math.Min(255 - 1, startIndex.Y); startIndex.X = Math.Max(startIndex.X, 1); startIndex.Y = Math.Max(startIndex.X + 1, startIndex.Y); return startIndex; } /// /// 更新直方图特征曲线 /// /// 是否需要更新三个控制点的位置 private void updateHistogramRect(bool updateThreePoints) { //为了更好显示直方图细节,使用4倍尺寸绘制直方图 int histSize = 256/*oldHists[0].Rows*/ * 4; //创建用于绘制的深蓝色背景图像 Mat image = new Mat(histSize, histSize, MatType.CV_8UC4, new Scalar(0, 0, 0, 0)); //输入拟合点 List points = new List(); //根据亮度和对比度计算左右阈值 int grayMin = (int)ucTrackBar1.Value1; int grayMax = (int)ucTrackBar1.Value3; if (grayMin >= grayMax) { return; } if (updateThreePoints) { ucTrackBar1.Value1 = grayMin; ucTrackBar1.Value3 = grayMax; //ucTrackBar1.Value2 = (float)((grayMin + grayMax) / 2.0); } if (this.IsDisposed) return; //gamma运算,gamma值根据AxioVision对比 取最小值0.01进行计算 double gamma = Math.Max(0.01, double.Parse(label7.Text)); //计算Value2 // ucTrackBar1.Value2 = (float)Math.Max(grayMin, Math.Min(grayMax, Math.Pow(0.5, 1.0 / gamma) * (grayMax - grayMin) + grayMin)); this.Invoke(new Action(() => { ucTrackBar1.Refresh(); })); int lastY2 = histSize + 0;// histSize - 1; for (int h = 0; h <= 256; h++) { if (h < grayMin) { points.Add(new OpenCvSharp.Point(h * 4, lastY2)); continue; } else if (h > grayMax) { lastY2 = -1;// 0; points.Add(new OpenCvSharp.Point(h * 4, lastY2)); continue; } int lastY1 = (int)Math.Round((1.0 - Math.Pow((h - grayMin) * 1.0 / (grayMax - grayMin), gamma)) * (histSize + 1/*histSize - 1*/)) - 1; lastY1 = Math.Min(lastY2, Math.Max(0, lastY1)); if (lastY2 == lastY1) { if (h == 0 || h == 256) { points.Add(new OpenCvSharp.Point(h * 4, lastY1)); } } else { points.Add(new OpenCvSharp.Point(h * 4, lastY1)); lastY2 = lastY1; } } lastY2 = histSize + 0;// histSize - 1; //将第一个点的位置设置最底部,保证曲线平滑性 //if (points[0].X > 4 && points[0].Y < lastY2) //{ // points.Insert(0, new OpenCvSharp.Point(points[0].X - 4, lastY2)); //} List> pointsIn = new List>() { points }; //绘制折线 Cv2.Polylines(image, pointsIn/*(IEnumerable)(points.ToArray())*/, false, new Scalar(0, 0/*255*/, 0, 255), 4/*1*/, LineTypes.Link8, 0); //cv::polylines(image, points, false, cv::Scalar(0, 255, 0), 1, 8, 0); //this.pictureBox1.Image = OpenCvSharp.Extensions.BitmapConverter.ToBitmap(image); Mat A = new Mat(3 + 1, 1, MatType.CV_64FC1, new Scalar(0)); polynomial_curve_fit(points.ToArray(), 3, A); this.pictureBox1.Image = OpenCvSharp.Extensions.BitmapConverter.ToBitmap(image); } /// /// 拖动左侧三角形 /// /// /// private void LeftLevelChanged(object sender, EventArgs e) { var valueL = ucTrackBar1.Value1; var valueR = ucTrackBar1.Value3; if (valueR - valueL < 1) { valueL = valueR - 1; ucTrackBar1.Value1 = valueL; } m_camera.LeftLevel = (int)valueL; } /// /// 拖动右侧三角形 /// /// /// private void RightLevelChanged(object sender, EventArgs e) { var valueL = ucTrackBar1.Value1; var valueR = ucTrackBar1.Value3; if (valueR - valueL < 1) { valueR = valueL + 1; ucTrackBar1.Value3 = valueR; } m_camera.RightLevel = (int)valueR; } private void ucTrackBar1_Value2Changed(object sender, EventArgs e) { if (ucTrackBar1.Value2 < 64) { ucTrackBar1.Value2 = 64; } var value = (int)ucTrackBar1.Value2; trackBar3.Value = value; label7.Text = (value / 100.0).ToString("f2"); m_camera.Gamma = value; } protected override void Dispose(bool disposing) { m_aeTimer?.Dispose(); base.Dispose(disposing); } } }