使用本文代码需要预先设置一点开发环境,请阅读另外一篇博文:
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();
}
}
}