【技术分享】C# OpenCvSharp实现图像对比度和亮度整,让你的图片恢复自然!

效果

45565ae9fc3db88285f8f568493e88e2.png

项目

95c5ecb8c0ed4a4e7cc71a4d1cde4cf7.png

代码

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using OpenCvSharp;

namespace OpenCvSharp_改变图像的对比度和亮度
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        Mat src;//源图

        double alpha = 0;
        double beta = 0;
        double gamma = 0;

        double maxVal = -1;//源图最多像素点个数

        Mat new_Image1;
        Mat new_Image2;

        Mat dst;
        Mat hist;
        Mat histImg;

        private void OnChange()
        {
            //初始化所有值都为0的矩阵
            new_Image1 = Mat.Zeros(src.Size(), src.Type());
            new_Image2 = Mat.Zeros(src.Size(), src.Type());
            //m:转换类型后的输出的图像;rtype转换图像的数据类型;alpha:转换过程中的缩放因子;beta:转换过程中的偏置因子
            //m(x,y)=saturate_cast<rType>(alpha*(*this)(x,y)+beta);
            src.ConvertTo(new_Image2, src.Type(), alpha, beta);
            GetHistResult(new_Image2, out hist, out histImg);
            if (pictureBox2.Image != null)
            {
                pictureBox2.Image.Dispose();
            }
            pictureBox2.Image = OpenCvSharp.Extensions.BitmapConverter.ToBitmap(histImg);
            if (pictureBox3.Image != null)
            {
                pictureBox3.Image.Dispose();
            }
            pictureBox3.Image = OpenCvSharp.Extensions.BitmapConverter.ToBitmap(new_Image2);
        }

        const int histW = 512;
        const int histH = 400;
        int histSize = 256;//直方图数组大小
        Rangef range = new Rangef(0, 256);//统计0至255(=266-1)

        /// <summary>
        /// 计算并生成绘制直方图
        /// </summary>
        /// <param name="src">待统计的图像</param>
        /// <param name="hist">直方图结果</param>
        /// <param name="histImage">直方图的绘制结果</param>
        private void GetHistResult(Mat src, out Mat hist, out Mat histImage)
        {
            hist = new Mat();
            histImage = new Mat(histH, histW, MatType.CV_8UC3, Scalar.All(0));
            //将图像像素灰度[0,255]共分为histSize个等级统计,
            for (int channel = 0; channel < src.Channels(); channel++)
            {
                Cv2.CalcHist(images: new[] { src },//待统计的图像
                            channels: new[] { channel },//待统计的通道
                            mask: null,//掩膜
                            hist: hist,//输出的统计结果
                            dims: 1,//直方图维度
                            histSize: new[] { histSize },//将range分为histSize梯度
                            ranges: new[] { range });//待统计通道像素的范围,不在这个范围内的不统计
                DrawHist(histImage, hist, (channel == 0 ? Scalar.Blue : (channel == 1 ? Scalar.Green : Scalar.Red)));
            }
        }

        /// <summary>
        /// 绘制直方图
        /// </summary>
        /// <param name="histImage">直方图绘制结果</param>
        /// <param name="histSize">直方图数组大小</param>
        /// <param name="color">线的颜色</param>
        private void DrawHist(Mat histImage, Mat hist, Scalar color)
        {
            var binW = Math.Round((double)histImage.Width / hist.Height);
            if (maxVal > 0)
            {
                //截断超过源图最大值的像素大数(防止饱和像素过多)
                Cv2.Threshold(hist, hist, maxVal, maxVal, ThresholdTypes.Trunc);
            }
            //归一化
            Cv2.Normalize(hist, hist, 0, histImage.Rows, NormTypes.MinMax, -1);
            for (int i = 1; i < hist.Height; i++)
            {
                var pt1 = new Point2d(binW * (i - 1), histImage.Height - Math.Round(hist.At<float>(i - 1)));
                var pt2 = new Point2d(binW * (i), histImage.Height - Math.Round(hist.At<float>(i)));
                Cv2.Line(histImage, (OpenCvSharp.Point)pt1, (OpenCvSharp.Point)pt2, color, 1, LineTypes.AntiAlias);
            }
        }

        /// <summary> 
        /// Gamma矫正 
        /// </summary>
        /// <param name="src"></param>
        /// <param name="gamma"></param>
        /// <returns></returns>
        private Mat GammaCorrection(Mat src, double gamma)
        {
            var lookUpTable = new Mat(new OpenCvSharp.Size(1, 256), MatType.CV_8U);
            for (int i = 0; i < 256; i++)
            {
                lookUpTable.Set<byte>(0, i, Convert.ToByte(Math.Pow(i / 255.0D, gamma) * 255.0D));
            }
            Mat dst = new Mat();
            //查表法,性能优化
            Cv2.LUT(src, lookUpTable, dst);
            return dst;
        }

        private void gammaOnChange()
        {
            dst = GammaCorrection(src, gamma);
            GetHistResult(dst, out hist, out  histImg);
            if (pictureBox2.Image != null)
            {
                pictureBox2.Image.Dispose();
            }
            pictureBox2.Image = OpenCvSharp.Extensions.BitmapConverter.ToBitmap(histImg);
            if (pictureBox3.Image != null)
            {
                pictureBox3.Image.Dispose();
            }
            pictureBox3.Image = OpenCvSharp.Extensions.BitmapConverter.ToBitmap(dst);
        }

        private void PutText(Mat src, string text)
        {
            PutText(src, text, new OpenCvSharp.Point(10, 20));
        }

        private void PutText(Mat src, string text, OpenCvSharp.Point point)
        {
            Cv2.PutText(src, text, point, HersheyFonts.HersheySimplex, 2, Scalar.Red);
        }

        string fileFilter = "*.*|*.bmp;*.jpg;*.jpeg;*.tiff;*.tiff;*.png";
        string imgPath = "";

        private void button2_Click(object sender, EventArgs e)
        {
            OpenFileDialog ofd = new OpenFileDialog();
            ofd.Filter = fileFilter;
            if (ofd.ShowDialog() != DialogResult.OK) return;
            pictureBox1.Image = null;
            imgPath = ofd.FileName;
            pictureBox1.Image = new Bitmap(imgPath);
            src = new Mat(imgPath);
        }

        /// <summary>
        /// alpha
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void trackBar1_Scroll(object sender, EventArgs e)
        {
            alpha = trackBar1.Value / 100.0D;
            textBox1.Text = alpha.ToString("0.00");
            if (pictureBox1.Image == null) return;
            OnChange();
        }

        /// <summary>
        /// beta
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void trackBar2_Scroll(object sender, EventArgs e)
        {
            beta = trackBar2.Value - 255;
            textBox2.Text = beta.ToString();
            if (pictureBox1.Image == null) return;
            OnChange();
        }

        /// <summary>
        /// gamma
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void trackBar3_Scroll(object sender, EventArgs e)
        {
            gamma = trackBar3.Value / 100.0D;
            textBox3.Text = gamma.ToString("0.00");
            if (pictureBox1.Image == null) return;
            gammaOnChange();
        }

        private void Form1_Load(object sender, EventArgs e)
        {
            imgPath = "test.jpg";
            pictureBox1.Image = new Bitmap(imgPath);
            src = new Mat(imgPath);
        }
    }
}

参考

https://docs.opencv.org/4.7.0/d3/dc1/tutorial_basic_linear_transform.html

1e67d86d4846266b8f50ee7293c8b8fd.gif

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值