C#图像处理OpenCV开发指南(CVStar,04)——图片像素访问与多种局部放大效果的实现代码

​​​​​​​

使用本文代码需要预先设置一点开发环境,请阅读另外一篇博文:

C#图像处理OpenCV开发指南(CVStar,03)------基于.NET 6的图像处理桌面程序开发实践第一步https://blog.csdn.net/beijinghorn/article/details/134684471?spm=1001.2014.3001.5502

1 功能需求

(1)读取图片;并显示于窗口;可缩放;

(2)可访问图片指定位置像素信息;

(3)提取局部图片(ROI)

(4)有 拾取框;

(5)局部放大(连续型放大);

(6)支持 大像素 型得局部放大;

(7)支持 圆形 像素的局部放大;

2 代码分段讲解

前面一个博文中出现过的代码不再赘述。

2.1 访问图片指定位置像素信息

cs 复制代码
Vec3b cx = zmt.At<Vec3b>(y, x);

y,x 指定的位置;顺序不要搞错啦!

返回的数据类型 Vec3b 是 byte[] 类型的;BGR顺序;cx[0] 为 Blue,cx[1] 为 Green;cx[2] 为 Red;这个与一般的图片信息 RGB 顺序不同;

2.2 提取局部图片(ROI)

cs 复制代码
Mat zmt = new Mat(src, new Rect(gx, gy, gw, gh));

gx,gy 为左上角坐标;

gw,gh 为局部图片的宽度与高度(像素)。

2.3 拾取框绘制

cs 复制代码
int gw = picResult.Width / PixelSize;
int gh = picResult.Height / PixelSize;
Bitmap bmp = new Bitmap(picSource.Width, picSource.Height);
Graphics g = Graphics.FromImage(bmp);
g.DrawImage(
    image: img,
    destRect: new Rectangle(0, 0, bmp.Width, bmp.Height),
    srcX: 0,
    srcY: 0,
    srcWidth: img.Width,
    srcHeight: img.Height,
    srcUnit: GraphicsUnit.Pixel);
g.DrawRectangle(new Pen(Color.Yellow), mouseAtX - gw / 2, mouseAtY - gh / 2, gw, gh);
picSource.Image = bmp;

2.4 光滑的(插值的)局部放大

图片的局部放大是取局部图片,放大显示。或者直接将图片放大显示并进行移位。

非 OpenCV 方式:

cs 复制代码
Bitmap bmp = new Bitmap(picResult.Width, picResult.Height);
Graphics g = Graphics.FromImage(bmp);
g.DrawImage(
    image: picSource.Image,
    destRect: new Rectangle(0, 0, bmp.Width, bmp.Height),
    srcX: gx,
    srcY: gy,
    srcWidth: gw,
    srcHeight: gh,
    srcUnit: GraphicsUnit.Pixel);
picResult.Image = bmp;

OpenCV方式

cs 复制代码
Mat zmt = new Mat(src, new Rect(gx, gy, gw, gh));
picResult.Image = CVUtility.Mat2Bitmap(zmt);
PicAutosize(picResult);

2.5 非插值的大像素型放大

非插值的大像素型放大是指将原图的每个像素放大为一个矩形(块)显示。

cs 复制代码
Mat zmt = new Mat(src, new Rect(gx, gy, gw, gh));
Bitmap bmp = new Bitmap(picResult.Width, picResult.Height);
Graphics g = Graphics.FromImage(bmp);
g.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.HighQualityBicubic;
g.CompositingQuality = System.Drawing.Drawing2D.CompositingQuality.HighQuality;
for (int y = 0; y < gh; y++)
{
    for (int x = 0; x < gw; x++)
    {
        Vec3b cx = zmt.At<Vec3b>(y, x);
        SolidBrush sb = new SolidBrush(Color.FromArgb(cx[2], cx[1], cx[0]));
        g.FillRectangle(sb, new Rectangle(x * PixelSize, y * PixelSize, PixelSize, PixelSize));
    }
}
picResult.Image = bmp;

2.6 圆圈型像素放大算法

圆圈型像素放大算法是指将原图的每个像素放大为一个圆圈(派)显示。

cs 复制代码
Mat zmt = new Mat(src, new Rect(gx, gy, gw, gh));
Bitmap bmp = new Bitmap(picResult.Width, picResult.Height);
Graphics g = Graphics.FromImage(bmp);
g.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.HighQualityBicubic;
g.CompositingQuality = System.Drawing.Drawing2D.CompositingQuality.HighQuality;
for (int y = 0; y < gh; y++)
{
    for (int x = 0; x < gw; x++)
    {
        Vec3b cx = zmt.At<Vec3b>(y, x);
        SolidBrush sb = new SolidBrush(Color.FromArgb(cx[2], cx[1], cx[0]));
        g.FillEllipse(sb, new Rectangle(x * PixelSize, y * PixelSize, PixelSize, PixelSize));
    }
}
picResult.Image = bmp;

2.7 鼠标事件与拾取框

cs 复制代码
private void PicSource_MouseMove(object? sender, MouseEventArgs? e)
{
    if (picSource == null) { return; }
    if (picSource.Image == null) { return; }
    mouseAtX = e.X;
    mouseAtY = e.Y;
    abLocation.Text = mouseAtX + "," + mouseAtY + " " + (int)(mouseAtX / original_scale) + "," + (int)(mouseAtY / original_scale);

    int gw = picResult.Width / PixelSize;
    int gh = picResult.Height / PixelSize;
    Bitmap bmp = new Bitmap(picSource.Width, picSource.Height);
    Graphics g = Graphics.FromImage(bmp);
    g.DrawImage(
        image: img,
        destRect: new Rectangle(0, 0, bmp.Width, bmp.Height),
        srcX: 0,
        srcY: 0,
        srcWidth: img.Width,
        srcHeight: img.Height,
        srcUnit: GraphicsUnit.Pixel);
    g.DrawRectangle(new Pen(Color.Yellow), mouseAtX - gw / 2, mouseAtY - gh / 2, gw, gh);
    picSource.Image = bmp;

    Zoom();
}

3 运行效果

3.1 一般的插值放大算法效果

3.2 块状大像素放大效果

3.3 圆圈像素放大效果

4 完整的源代码

无需做修改,界面设计,直接复制粘贴替换原来的 Form1.cs 即可。

cs 复制代码
using OpenCvSharp;

#pragma warning disable CS8602

namespace Legal.Truffer.CVStar
{
    public partial class Form1 : Form
    {
        string[] ImgExtentions = {
            "*.*|*.*",
            "JPEG|*.jpg;*.jpeg",
            "GIF|*.gif",
            "PNG|*.png",
            "TIF|*.tif;*.tiff",
            "BMP|*.bmp"
        };
        private int original_width { get; set; } = 0;
        private int original_height { get; set; } = 0;
        private double original_scale { get; set; } = 0.0;
        private string sourceImage { get; set; } = "";

        private int PixelSize { get; set; } = 15;
        private int mouseAtX { get; set; } = 0;
        private int mouseAtY { get; set; } = 0;

        Panel? panelTop { get; set; } = null;
        Panel? panelBotton { get; set; } = null;
        PictureBox? picSource { get; set; } = null;
        PictureBox? picResult { get; set; } = null;
        Button? btnLoad { get; set; } = null;

        RadioButton? rbSmooth { get; set; } = null;
        RadioButton? rbBlock { get; set; } = null;
        RadioButton? rbPie { get; set; } = null;

        Label? abLocation { get; set; }

        Image? img { get; set; } = null;
        Mat? src { get; set; } = null;

        public Form1()
        {
            InitializeComponent();

            this.Text = "OPENCV C#编程入手教程 POWERED BY 深度混淆(CSDN.NET)";
            this.StartPosition = FormStartPosition.CenterScreen;

            GUI();
            this.Resize += FormResize;
            this.DoubleBuffered = true;
        }

        private void FormResize(object? sender, EventArgs? e)
        {
            if (this.Width < 200) { this.Width = 320; return; }
            if (this.Height < 200) { this.Height = 320; return; }
            mouseAtX = 0;
            mouseAtY = 0;
            GUI();
        }

        private void GUI()
        {
            if (panelTop == null) panelTop = new Panel();
            panelTop.Parent = this;
            panelTop.Top = 5;
            panelTop.Left = 5;
            panelTop.Height = 75;
            panelTop.Dock = DockStyle.Top;
            panelTop.BorderStyle = BorderStyle.FixedSingle;
            panelTop.BackColor = Color.FromArgb(220, 220, 255);

            if (panelBotton == null) panelBotton = new Panel();
            panelBotton.Parent = this;
            panelBotton.Top = panelTop.Top + panelTop.Height + 1;
            panelBotton.Left = 0;
            panelBotton.Width = panelTop.Width;
            panelBotton.Height = this.Height - panelBotton.Top - 55;
            panelBotton.BorderStyle = BorderStyle.FixedSingle;

            if (picSource == null) picSource = new PictureBox();
            picSource.Parent = panelBotton;
            picSource.Left = 5;
            picSource.Top = 5;
            picSource.Width = (panelBotton.Width - 10) / 2;
            picSource.Height = (panelBotton.Height - 10);
            picSource.BorderStyle = BorderStyle.FixedSingle;
            picSource.MouseMove += PicSource_MouseMove;
            picSource.DoubleClick += Load_Image;

            original_width = picSource.Width;
            original_height = picSource.Height;

            if (picResult == null) picResult = new PictureBox();
            picResult.Parent = panelBotton;
            picResult.Left = picSource.Left + picSource.Width + 5;
            picResult.Top = picSource.Top;
            picResult.Width = picSource.Width - (picSource.Width % PixelSize);
            picResult.Height = picResult.Width;
            picResult.BorderStyle = BorderStyle.FixedSingle;

            if (btnLoad == null) btnLoad = new Button();
            btnLoad.Parent = panelTop;
            btnLoad.Left = 5;
            btnLoad.Top = 5;
            btnLoad.Width = 90;
            btnLoad.Height = 38;
            btnLoad.Cursor = Cursors.Hand;
            btnLoad.Text = "Load";
            btnLoad.BackColor = Color.FromArgb(255, 110, 0);
            btnLoad.Click += Load_Image;

            if (rbSmooth == null) rbSmooth = new RadioButton();
            rbSmooth.Parent = panelTop;
            rbSmooth.Left = btnLoad.Left + btnLoad.Width + 5;
            rbSmooth.Top = btnLoad.Top + 5;
            rbSmooth.Text = "smooth";
            rbSmooth.Cursor = Cursors.Hand;
            rbSmooth.Checked = true;

            if (rbBlock == null) rbBlock = new RadioButton();
            rbBlock.Parent = panelTop;
            rbBlock.Left = rbSmooth.Left + rbSmooth.Width + 5;
            rbBlock.Top = btnLoad.Top + 5;
            rbBlock.Text = "block";
            rbBlock.Cursor = Cursors.Hand;

            if (rbPie == null) rbPie = new RadioButton();
            rbPie.Parent = panelTop;
            rbPie.Left = rbBlock.Left + rbBlock.Width + 5;
            rbPie.Top = btnLoad.Top + 5;
            rbPie.Text = "pie";
            rbPie.Cursor = Cursors.Hand;

            if (abLocation == null) abLocation = new Label();
            abLocation.Parent = panelTop;
            abLocation.Left = btnLoad.Left;
            abLocation.Top = btnLoad.Top + btnLoad.Height + 5;
            abLocation.Text = mouseAtX + "," + mouseAtY;

            PicAutosize(picSource);
            Zoom();
        }

        private void Load_Image(object? sender, EventArgs? e)
        {
            OpenFileDialog openFileDialog = new OpenFileDialog();
            openFileDialog.Filter = String.Join("|", ImgExtentions);
            if (openFileDialog.ShowDialog() == DialogResult.OK)
            {
                sourceImage = openFileDialog.FileName;
                img = Image.FromFile(sourceImage);
                picSource.Image = img;
                src = Cv2.ImRead(sourceImage);
                PicAutosize(picSource);
                Zoom();
            }
        }

        private void PicAutosize(PictureBox pb)
        {
            if (pb == null) return;
            if (pb.Image == null) return;
            Image img = pb.Image;
            int w = original_width;
            int h = w * img.Height / img.Width;
            if (h > original_height)
            {
                h = original_height;
                w = h * img.Width / img.Height;
            }
            if (pb == picSource)
            {
                original_scale = (double)w / (double)src.Width;
            }
            pb.SizeMode = PictureBoxSizeMode.Zoom;
            pb.Width = w;
            pb.Height = h;
            pb.Image = img;
            pb.Refresh();
        }

        private void Zoom()
        {
            if (picSource == null) return;
            if (picSource.Image == null) return;

            // ROI
            int gw = picResult.Width / PixelSize;
            int gh = picResult.Height / PixelSize;
            int gx = (int)(mouseAtX / original_scale) - gw / 2;
            if (gx < 0) gx = 0;
            int gy = (int)(mouseAtY / original_scale) - gh / 2;
            if (gy < 0) gy = 0;

            if (rbSmooth.Checked)
            {
#if GRAPHICS_METHOD
                Bitmap bmp = new Bitmap(picResult.Width, picResult.Height);
                Graphics g = Graphics.FromImage(bmp);
                g.DrawImage(
                    image: picSource.Image,
                    destRect: new Rectangle(0, 0, bmp.Width, bmp.Height),
                    srcX: gx,
                    srcY: gy,
                    srcWidth: gw,
                    srcHeight: gh,
                    srcUnit: GraphicsUnit.Pixel);
                picResult.Image = bmp;
#else
                Mat zmt = new Mat(src, new Rect(gx, gy, gw, gh));
                picResult.Image = CVUtility.Mat2Bitmap(zmt);
                PicAutosize(picResult);
#endif
            }
            else if (rbBlock.Checked)
            {
                Mat zmt = new Mat(src, new Rect(gx, gy, gw, gh));
                Bitmap bmp = new Bitmap(picResult.Width, picResult.Height);
                Graphics g = Graphics.FromImage(bmp);
                g.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.HighQualityBicubic;
                g.CompositingQuality = System.Drawing.Drawing2D.CompositingQuality.HighQuality;
                for (int y = 0; y < gh; y++)
                {
                    for (int x = 0; x < gw; x++)
                    {
                        Vec3b cx = zmt.At<Vec3b>(y, x);
                        SolidBrush sb = new SolidBrush(Color.FromArgb(cx[2], cx[1], cx[0]));
                        g.FillRectangle(sb, new Rectangle(x * PixelSize, y * PixelSize, PixelSize, PixelSize));
                    }
                }
                picResult.Image = bmp;
            }
            else if (rbPie.Checked)
            {
                Mat zmt = new Mat(src, new Rect(gx, gy, gw, gh));
                Bitmap bmp = new Bitmap(picResult.Width, picResult.Height);
                Graphics g = Graphics.FromImage(bmp);
                g.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.HighQualityBicubic;
                g.CompositingQuality = System.Drawing.Drawing2D.CompositingQuality.HighQuality;
                for (int y = 0; y < gh; y++)
                {
                    for (int x = 0; x < gw; x++)
                    {
                        Vec3b cx = zmt.At<Vec3b>(y, x);
                        SolidBrush sb = new SolidBrush(Color.FromArgb(cx[2], cx[1], cx[0]));
                        g.FillEllipse(sb, new Rectangle(x * PixelSize, y * PixelSize, PixelSize, PixelSize));
                    }
                }
                picResult.Image = bmp;
            }
        }

        private void PicSource_MouseMove(object? sender, MouseEventArgs? e)
        {
            if (picSource == null) { return; }
            if (picSource.Image == null) { return; }
            mouseAtX = e.X;
            mouseAtY = e.Y;
            abLocation.Text = mouseAtX + "," + mouseAtY + " " + (int)(mouseAtX / original_scale) + "," + (int)(mouseAtY / original_scale);

            int gw = picResult.Width / PixelSize;
            int gh = picResult.Height / PixelSize;
            Bitmap bmp = new Bitmap(picSource.Width, picSource.Height);
            Graphics g = Graphics.FromImage(bmp);
            g.DrawImage(
                image: img,
                destRect: new Rectangle(0, 0, bmp.Width, bmp.Height),
                srcX: 0,
                srcY: 0,
                srcWidth: img.Width,
                srcHeight: img.Height,
                srcUnit: GraphicsUnit.Pixel);
            g.DrawRectangle(new Pen(Color.Yellow), mouseAtX - gw / 2, mouseAtY - gh / 2, gw, gh);
            picSource.Image = bmp;

            Zoom();
        }
    }
}
相关推荐
代码小将几秒前
Leetcode209做题笔记
java·笔记·算法
Musennn1 小时前
leetcode 15.三数之和 思路分析
算法·leetcode·职场和发展
敲代码的 蜡笔小新3 小时前
【行为型之中介者模式】游戏开发实战——Unity复杂系统协调与通信架构的核心秘诀
unity·设计模式·c#·中介者模式
CM莫问4 小时前
<论文>(微软)避免推荐域外物品:基于LLM的受限生成式推荐
人工智能·算法·大模型·推荐算法·受限生成
程序猿多布4 小时前
使用Visual Studio将C#程序发布为.exe文件
c#·visual studio
康谋自动驾驶5 小时前
康谋分享 | 自动驾驶仿真进入“标准时代”:aiSim全面对接ASAM OpenX
人工智能·科技·算法·机器学习·自动驾驶·汽车
老衲有点帅5 小时前
C#多线程Thread
开发语言·c#
C++ 老炮儿的技术栈5 小时前
什么是函数重载?为什么 C 不支持函数重载,而 C++能支持函数重载?
c语言·开发语言·c++·qt·算法
深蓝学院6 小时前
密西根大学新作——LightEMMA:自动驾驶中轻量级端到端多模态模型
人工智能·机器学习·自动驾驶
yychen_java6 小时前
R-tree详解
java·算法·r-tree