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();
        }
    }
}
相关推荐
NAGNIP6 小时前
一文搞懂深度学习中的通用逼近定理!
人工智能·算法·面试
冬奇Lab7 小时前
一天一个开源项目(第36篇):EverMemOS - 跨 LLM 与平台的长时记忆 OS,让 Agent 会记忆更会推理
人工智能·开源·资讯
冬奇Lab7 小时前
OpenClaw 源码深度解析(一):Gateway——为什么需要一个"中枢"
人工智能·开源·源码阅读
AngelPP11 小时前
OpenClaw 架构深度解析:如何把 AI 助手搬到你的个人设备上
人工智能
宅小年11 小时前
Claude Code 换成了Kimi K2.5后,我再也回不去了
人工智能·ai编程·claude
九狼11 小时前
Flutter URL Scheme 跨平台跳转
人工智能·flutter·github
ZFSS11 小时前
Kimi Chat Completion API 申请及使用
前端·人工智能
天翼云开发者社区12 小时前
春节复工福利就位!天翼云息壤2500万Tokens免费送,全品类大模型一键畅玩!
人工智能·算力服务·息壤
知识浅谈12 小时前
教你如何用 Gemini 将课本图片一键转为精美 PPT
人工智能
Ray Liang13 小时前
被低估的量化版模型,小身材也能干大事
人工智能·ai·ai助手·mindx