C# CvDnn部署CoupledTPS实现旋转图像矫正

C# CvDnn部署CoupledTPS实现旋转图像矫正

目录

说明

效果

模型信息

项目

代码

下载


说明

TPAMI2024 - Semi-Supervised Coupled Thin-Plate Spline Model for Rotation Correction and Beyond

github地址:https://github.com/nie-lang/CoupledTPS

代码实现参考:https://github.com/hpc203/CoupledTPS-opencv-dnn

效果

模型信息

feature_extractor.onnx

Model Properties
-------------------------
---------------------------------------------------------------

Inputs
-------------------------
name:input
tensor:Float[1, 3, 384, 512]
---------------------------------------------------------------

Outputs
-------------------------
name:feature
tensor:Float[1, 256, 24, 32]
---------------------------------------------------------------

regressnet.onnx

Model Properties
-------------------------
---------------------------------------------------------------

Inputs
-------------------------
name:feature
tensor:Float[1, 256, 24, 32]
---------------------------------------------------------------

Outputs
-------------------------
name:mesh_motion
tensor:Float[1, 7, 9, 2]
---------------------------------------------------------------

项目

代码

Form1.cs

using OpenCvSharp;
using System;
using System.Drawing;
using System.Drawing.Imaging;
using System.Windows.Forms;

namespace Onnx_Demo
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        string fileFilter = "*.*|*.bmp;*.jpg;*.jpeg;*.tiff;*.tiff;*.png";
        string image_path = "";
        DateTime dt1 = DateTime.Now;
        DateTime dt2 = DateTime.Now;
        Mat image;

        CoupledTPS_RotationNet rotationNet;
        int iter_num = 3;

        private void button1_Click(object sender, EventArgs e)
        {
            OpenFileDialog ofd = new OpenFileDialog();
            ofd.InitialDirectory =Application.StartupPath+"\\test_img\\";
            ofd.Filter = fileFilter;
            
            if (ofd.ShowDialog() != DialogResult.OK) return;
            pictureBox1.Image = null;
            image_path = ofd.FileName;
            pictureBox1.Image = new Bitmap(image_path);
            textBox1.Text = "";
            image = new Mat(image_path);
            pictureBox2.Image = null;
        }

        private void button2_Click(object sender, EventArgs e)
        {
            if (image_path == "")
            {
                return;
            }
            button2.Enabled = false;
            pictureBox2.Image = null;
            textBox1.Text = "";
            Application.DoEvents();
            //读图片
            image = new Mat(image_path);
            dt1 = DateTime.Now;
            Mat result_image = rotationNet.detect(image, iter_num);
            dt2 = DateTime.Now;
            Cv2.CvtColor(result_image, result_image, ColorConversionCodes.BGR2RGB);
            pictureBox2.Image = new Bitmap(result_image.ToMemoryStream());
            textBox1.Text = "推理耗时:" + (dt2 - dt1).TotalMilliseconds + "ms";
            button2.Enabled = true;
        }

        private void Form1_Load(object sender, EventArgs e)
        {
            rotationNet = new CoupledTPS_RotationNet("model/feature_extractor.onnx", "model/regressnet.onnx");
            image_path = "test_img/00150_-8.4.jpg";
            pictureBox1.Image = new Bitmap(image_path);
            image = new Mat(image_path);
        }

        private void pictureBox1_DoubleClick(object sender, EventArgs e)
        {
            Common.ShowNormalImg(pictureBox1.Image);
        }

        private void pictureBox2_DoubleClick(object sender, EventArgs e)
        {
            Common.ShowNormalImg(pictureBox2.Image);
        }

        SaveFileDialog sdf = new SaveFileDialog();
        private void button3_Click(object sender, EventArgs e)
        {
            if (pictureBox2.Image == null)
            {
                return;
            }
            Bitmap output = new Bitmap(pictureBox2.Image);
            sdf.Title = "保存";
            sdf.Filter = "Images (*.jpg)|*.jpg|Images (*.png)|*.png|Images (*.bmp)|*.bmp|Images (*.emf)|*.emf|Images (*.exif)|*.exif|Images (*.gif)|*.gif|Images (*.ico)|*.ico|Images (*.tiff)|*.tiff|Images (*.wmf)|*.wmf";
            if (sdf.ShowDialog() == DialogResult.OK)
            {
                switch (sdf.FilterIndex)
                {
                    case 1:
                        {
                            output.Save(sdf.FileName, ImageFormat.Jpeg);
                            break;
                        }
                    case 2:
                        {
                            output.Save(sdf.FileName, ImageFormat.Png);
                            break;
                        }
                    case 3:
                        {
                            output.Save(sdf.FileName, ImageFormat.Bmp);
                            break;
                        }
                    case 4:
                        {
                            output.Save(sdf.FileName, ImageFormat.Emf);
                            break;
                        }
                    case 5:
                        {
                            output.Save(sdf.FileName, ImageFormat.Exif);
                            break;
                        }
                    case 6:
                        {
                            output.Save(sdf.FileName, ImageFormat.Gif);
                            break;
                        }
                    case 7:
                        {
                            output.Save(sdf.FileName, ImageFormat.Icon);
                            break;
                        }

                    case 8:
                        {
                            output.Save(sdf.FileName, ImageFormat.Tiff);
                            break;
                        }
                    case 9:
                        {
                            output.Save(sdf.FileName, ImageFormat.Wmf);
                            break;
                        }
                }
                MessageBox.Show("保存成功,位置:" + sdf.FileName);
            }
        }
    }
}

using OpenCvSharp;
using System;
using System.Drawing;
using System.Drawing.Imaging;
using System.Windows.Forms;namespace Onnx_Demo
{public partial class Form1 : Form{public Form1(){InitializeComponent();}string fileFilter = "*.*|*.bmp;*.jpg;*.jpeg;*.tiff;*.tiff;*.png";string image_path = "";DateTime dt1 = DateTime.Now;DateTime dt2 = DateTime.Now;Mat image;CoupledTPS_RotationNet rotationNet;int iter_num = 3;private void button1_Click(object sender, EventArgs e){OpenFileDialog ofd = new OpenFileDialog();ofd.InitialDirectory =Application.StartupPath+"\\test_img\\";ofd.Filter = fileFilter;if (ofd.ShowDialog() != DialogResult.OK) return;pictureBox1.Image = null;image_path = ofd.FileName;pictureBox1.Image = new Bitmap(image_path);textBox1.Text = "";image = new Mat(image_path);pictureBox2.Image = null;}private void button2_Click(object sender, EventArgs e){if (image_path == ""){return;}button2.Enabled = false;pictureBox2.Image = null;textBox1.Text = "";Application.DoEvents();//读图片image = new Mat(image_path);dt1 = DateTime.Now;Mat result_image = rotationNet.detect(image, iter_num);dt2 = DateTime.Now;Cv2.CvtColor(result_image, result_image, ColorConversionCodes.BGR2RGB);pictureBox2.Image = new Bitmap(result_image.ToMemoryStream());textBox1.Text = "推理耗时:" + (dt2 - dt1).TotalMilliseconds + "ms";button2.Enabled = true;}private void Form1_Load(object sender, EventArgs e){rotationNet = new CoupledTPS_RotationNet("model/feature_extractor.onnx", "model/regressnet.onnx");image_path = "test_img/00150_-8.4.jpg";pictureBox1.Image = new Bitmap(image_path);image = new Mat(image_path);}private void pictureBox1_DoubleClick(object sender, EventArgs e){Common.ShowNormalImg(pictureBox1.Image);}private void pictureBox2_DoubleClick(object sender, EventArgs e){Common.ShowNormalImg(pictureBox2.Image);}SaveFileDialog sdf = new SaveFileDialog();private void button3_Click(object sender, EventArgs e){if (pictureBox2.Image == null){return;}Bitmap output = new Bitmap(pictureBox2.Image);sdf.Title = "保存";sdf.Filter = "Images (*.jpg)|*.jpg|Images (*.png)|*.png|Images (*.bmp)|*.bmp|Images (*.emf)|*.emf|Images (*.exif)|*.exif|Images (*.gif)|*.gif|Images (*.ico)|*.ico|Images (*.tiff)|*.tiff|Images (*.wmf)|*.wmf";if (sdf.ShowDialog() == DialogResult.OK){switch (sdf.FilterIndex){case 1:{output.Save(sdf.FileName, ImageFormat.Jpeg);break;}case 2:{output.Save(sdf.FileName, ImageFormat.Png);break;}case 3:{output.Save(sdf.FileName, ImageFormat.Bmp);break;}case 4:{output.Save(sdf.FileName, ImageFormat.Emf);break;}case 5:{output.Save(sdf.FileName, ImageFormat.Exif);break;}case 6:{output.Save(sdf.FileName, ImageFormat.Gif);break;}case 7:{output.Save(sdf.FileName, ImageFormat.Icon);break;}case 8:{output.Save(sdf.FileName, ImageFormat.Tiff);break;}case 9:{output.Save(sdf.FileName, ImageFormat.Wmf);break;}}MessageBox.Show("保存成功,位置:" + sdf.FileName);}}}
}

CoupledTPS_RotationNet.cs

using OpenCvSharp;
using OpenCvSharp.Dnn;
using System.Collections.Generic;
using System.Linq;namespace Onnx_Demo
{public class CoupledTPS_RotationNet{int input_height = 384;int input_width = 512;int grid_h = 6;int grid_w = 8;Mat grid = new Mat();Mat W_inv = new Mat();Net feature_extractor;Net regressNet;public CoupledTPS_RotationNet(string modelpatha, string modelpathb){feature_extractor = CvDnn.ReadNet(modelpatha);regressNet = CvDnn.ReadNet(modelpathb);tps2flow.get_norm_rigid_mesh_inv_grid(ref grid, ref W_inv, input_height, input_width, grid_h, grid_w);}unsafe public Mat detect(Mat srcimg, int iter_num){Mat img = new Mat();Cv2.Resize(srcimg, img, new Size(input_width, input_height));img.ConvertTo(img, MatType.CV_32FC3, 1.0 / 127.5d, -1.0d);Mat input_tensor = CvDnn.BlobFromImage(img);feature_extractor.SetInput(input_tensor);Mat[] feature_oris = new Mat[1] { new Mat() };string[] outBlobNames = feature_extractor.GetUnconnectedOutLayersNames().ToArray();feature_extractor.Forward(feature_oris, outBlobNames);Mat feature = feature_oris[0].Clone();int[] shape = { 1, 2, input_height, input_width };Mat flow = Mat.Zeros(MatType.CV_32FC1, shape);List<Mat> flow_list = new List<Mat>();for (int i = 0; i < iter_num; i++){regressNet.SetInput(feature);Mat[] mesh_motions = new Mat[1] { new Mat() };regressNet.Forward(mesh_motions, regressNet.GetUnconnectedOutLayersNames().ToArray());float* offset = (float*)mesh_motions[0].Data;Mat tp = new Mat();tps2flow.get_ori_rigid_mesh_tp(ref tp, offset, input_height, input_width, grid_h, grid_w);Mat T = W_inv * tp;   //_solve_systemT = T.T();    //舍弃batchsizeMat T_g = T * grid;Mat delta_flow = new Mat();tps2flow._transform(T_g, grid, input_height, input_width, ref delta_flow);if (i == 0){flow += delta_flow;}else{Mat warped_flow = new Mat();grid_sample.warp_with_flow(flow, delta_flow, ref warped_flow);flow = delta_flow + warped_flow;}flow_list.Add(flow.Clone());if (i < (iter_num - 1)){int fea_h = feature.Size(2);int fea_w = feature.Size(3);float scale_h = (float)fea_h / flow.Size(2);float scale_w = (float)fea_w / flow.Size(3);Mat down_flow = new Mat();upsample.UpSamplingBilinear(flow, ref down_flow, fea_h, fea_w, true, scale_h, scale_w);for (int h = 0; h < fea_h; h++){for (int w = 0; w < fea_w; w++){float* p_w = (float*)down_flow.Ptr(0, 0, h);float temp_w = p_w[w];temp_w = temp_w * scale_w;p_w[w] = temp_w;float* p_h = (float*)down_flow.Ptr(0, 1, h);float temp_h = p_h[w];temp_h = temp_h * scale_h;p_h[w] = temp_h;}}feature.Release();feature = new Mat();grid_sample.warp_with_flow(feature_oris[0], down_flow, ref feature);}}Mat correction_final = new Mat();grid_sample.warp_with_flow(input_tensor, flow_list[iter_num - 1], ref correction_final);Mat correction_img = grid_sample.convert4dtoimage(correction_final);return correction_img;}}
}

下载

源码下载

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/pingmian/44816.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

240710_昇思学习打卡-Day22-LSTM+CRF序列标注

240710_昇思学习打卡-Day22-LSTMCRF序列标注 在正式开始LSTMCRF序列标注之前&#xff0c;我们先来了解一下条件随机场&#xff0c;以下仅做简单介绍。 CRF全称Conditional Random Field&#xff0c;按照名字来理解&#xff0c;条件随机&#xff0c;随机输入&#xff0c;条件输…

ReoGrid代替EXCEL显示数据,可视化修改ReoGrid.Mvvm:ReoGrid绑定模型

ReoGrid 是 C&#xff03; 编写的.NET 电子表格控件&#xff08;类似 Excel&#xff09;。支持单元格合并&#xff0c;边框样式&#xff0c;图案背景颜色&#xff0c;数据格式&#xff0c;冻结&#xff0c;公式&#xff0c;宏和脚本执行&#xff0c;表格事件等。支持 Winform\W…

游戏视频是后期配音好还是边录边配 游戏视频怎么剪辑制作才能火 视频剪辑免费软件

游戏视频后期配音是先配还是先剪&#xff1f;游戏视频后期配音没有统一的准则&#xff0c;可以先配&#xff0c;也可以后配&#xff0c;主要是根据内容而定。游戏视频剪辑在游戏玩家中十分流行&#xff0c;那么&#xff0c;游戏视频怎么剪辑制作&#xff1f;下面让我们以具体的…

ai写作软件哪个好用?这些写作工具值得收藏

在创意写作的世界里&#xff0c;每个字词都是作者情感与灵魂的载体。 但灵感的闪现与文字的成型之间&#xff0c;往往存在着一段漫长且充满挑战的旅程。幸运的是&#xff0c;人工智能技术的崛起带来了AI写作软件&#xff0c;它们不仅能够点燃创作的火花&#xff0c;还能辅助我…

探索 ASTRA.AI:打造低代码多模态 AI 应用的开源平台

声网&#xff08;Agora&#xff09;研发的 ASTRA 平台&#xff0c;作为一款面向大语言模型应用开发的开源解决方案&#xff0c;无疑为 AI 领域注入了新的活力。它巧妙地结合了 BaaS&#xff08;后端即服务&#xff09;概念与大型语言模型的运营&#xff0c;使得创建高性能的生成…

如何给CAD文件加密丨五种超级简单的CAD图纸加密方法

CAD图纸作为企业核心竞争力的体现&#xff0c;其安全性直接关系到企业的生产效率和市场竞争力。一旦图纸被泄露&#xff0c;竞争对手可能会迅速模仿或改进产品&#xff0c;从而抢占市场份额。此外&#xff0c;图纸的非法获取还可能涉及知识产权纠纷&#xff0c;给企业带来法律风…

镜像加速方法

参考&#xff1a; https://github.com/DaoCloud/public-image-mirror 使用DaoCloud加速&#xff1a; 比如我想在dockerhub下载这个镜像&#xff1a; 本来的命令是&#xff1a; docker pull openjdk:11.0-jdk-slim-buster在要拉取的镜像前&#xff0c;添加前缀&#xff1a;m.…

迅为RK3588S开发板广泛用于边缘技术,人工智能,智能家居,智慧零售,智能网关等

性能强 iTOP-3588S开发板采用瑞芯微RK3588S处理器&#xff0c;是全新一代AloT高端应用芯片&#xff0c;搭载八核64位CPU&#xff0c;四核Cortex-A76和四核Cortex-A55架构主频高达2.4GHZ&#xff0c;8GB内存&#xff0c;32GBEMMC。 四核心架构GPU内置GPU可以完全兼容0penGLES1.1…

MFC Ribbon菜单中英实时文切换方法

简介 最近在搞一个老外的项目&#xff0c;本来谈的好好的&#xff0c;纯英文界面。项目接近尾声了&#xff0c;又提出了中英文实时切换的新需求&#xff0c;没办法就只能想办法&#xff0c;毕竟客户最大嘛。 实现方法 还好本来的ribbon英文菜单不复杂&#xff0c;就用纯C编码…

struts2如何防止XSS脚本攻击(XSS防跨站脚本攻击过滤器)

只需要配置一个拦截器即可解决参数内容替换 一、配置web.xml <filter><filter-name>struts-xssFilter</filter-name><filter-class>*.*.filters.XssFilter</filter-class></filter><filter-mapping><filter-name>struts-xss…

专属大学生的创作活动,你在CSDN坚持创作,虚竹哥带你成长,带你涨粉

❤️作者主页&#xff1a;小虚竹 ❤️作者简介&#xff1a;大家好,我是小虚竹。2022年度博客之星评选TOP 10&#x1f3c6;&#xff0c;Java领域优质创作者&#x1f3c6;&#xff0c;CSDN博客专家&#x1f3c6;&#xff0c;华为云享专家&#x1f3c6;&#xff0c;掘金年度人气作…

PHP智慧社区小区物业管理系统小程序源码

让生活更便捷&#xff0c;社区更和谐✨ &#x1f3e1;【开篇&#xff1a;智慧生活&#xff0c;从社区开始】&#x1f3e1; 在快节奏的现代生活中&#xff0c;寻找一份便捷与舒适成为了我们共同的追求。小区&#xff0c;作为我们日常生活的温馨港湾&#xff0c;其管理水平和服…

安泰高压放大器设计要求是什么样的

高压放大器是一种在电子系统中用于放大高电压信号的重要组件。它通常用于应对需要处理高电压信号的应用&#xff0c;如医疗设备、实验室仪器和通信系统。设计高压放大器需要满足一系列严格的要求&#xff0c;以确保其性能稳定、可靠&#xff0c;并符合特定应用的需求。 以下是关…

适合学生写作业的台灯怎么选?一文读懂护眼台灯怎么选!

不知大家发现没有&#xff0c;近些年&#xff0c;戴眼镜的小孩儿是越来越多了&#xff0c;甚至有的地方好多刚上小学一年级的孩子&#xff0c;就已经戴着200度的近视镜了。据统计&#xff0c;如今&#xff0c;中国小学生近视比例为42%&#xff0c;初中生近视比例为80.7%&#x…

LabVIEW航空发动机试验器数据监测分析

1. 概述 为了适应航空发动机试验器的智能化发展&#xff0c;本文基于图形化编程工具LabVIEW为平台&#xff0c;结合航空发动机试验器原有的软硬件设备&#xff0c;设计开发了一套数据监测分析功能模块。主要阐述了数据监测分析功能设计中的设计思路和主要功能&#xff0c;以及…

捷配笔记-如何设计PCB板布线满足生产标准?

PCB板布线是铺设连接各种设备与通电信号的路径的过程。PCB板布线是铺设连接各种设备与通电信号的路径的过程。 在PCB设计中&#xff0c;布线是完成产品设计的重要步骤。可以说&#xff0c;之前的准备工作已经为它做好了。在整个PCB设计中&#xff0c;布线设计过程具有最高的极限…

[Err] 2006 - MySQL server has gone away 错误 MySQL server hasgoneaway报错原因分析及解决办法

导入sql文件报错&#xff1a; Your SQL statement was too large. 当查询的结果集超过 max_allowed_packet 也会出现这样的报错。定位方法是打出相关报错的语句。 用select * into outfile 的方式导出到文件&#xff0c;查看文件大小是否超过 max_allowed_packet &#xff0c;如…

楼道灯微波雷达模块模组,智能感应uA级超低功耗替换红外传感器,飞睿助力绿色照明

随着科技的飞速发展&#xff0c;LED楼道灯早已不仅仅是照亮我们回家路的工具&#xff0c;它们正变得越来越智能、高效和环保。今天&#xff0c;就让我们一起探索LED楼道灯背后的科技——飞睿智能微波雷达模块模组&#xff0c;以及它如何以超低功耗&#xff08;uA级别&#xff0…

甘肃美食于兰洽会数智电商馆展现魅力

在近日盛大开幕的兰洽会上&#xff0c;数智电商馆成为了备受瞩目的焦点&#xff0c;而甘肃平凉的特产更是在其中大放异彩。 平凉&#xff0c;这座拥有深厚历史文化底蕴的城市&#xff0c;带着其独具特色的物产走进了兰洽会的舞台。走进数智电商馆&#xff0c;首先映入眼帘的便是…

Latex(3): IEEE latex模版使用问题记录

文章目录 一、题目、作者、致谢格式问题1. xelatex与pdflatex模式不同导致字体显示不够粗2. xelatex模式下\IEEEmembership{Senior Member, IEEE}显示为正体&#xff0c;显示不了斜体 二、参考文献格式问题1. 作者显示为横线 记录IEEE latex的使用问题一、题目、作者、致谢格式…