目录
C# OpenCvSharp 部署文档矫正,包括文档扭曲/模糊/阴影等情况
说明
地址:https://github.com/RapidAI/RapidUnDistort
修正文档扭曲/模糊/阴影等情况,使用onnx模型简单轻量部署,未来持续跟进最新最好的文档矫正方案和模型,Correct document distortion using a lightweight ONNX model for easy deployment. We will continue to follow and integrate the latest and best document correction solutions and models in the future.
效果
模型
drnet.onnx
Model Properties
Inputs
name:input
tensor:Float[-1, 6, -1, -1]
Outputs
name:output
tensor:Float[-1, 3, -1, -1]
gcnet.onnx
Model Properties
Inputs
name:input
tensor:Float[-1, 3, -1, -1]
Outputs
name:output
tensor:Float[-1, 3, -1, -1]
nafdpm.onnx
Model Properties
Inputs
name:input
tensor:Float[-1, 3, -1, -1]
Outputs
name:output
tensor:Float[-1, -1, -1, -1]
unetcnn.onnx
Model Properties
Inputs
name:input
tensor:Float[-1, 3, -1, -1]
Outputs
name:output
tensor:Float[-1, 1, -1, -1]
uvdoc.onnx
Model Properties
Inputs
name:input
tensor:Float[-1, 3, -1, -1]
Outputs
name:output
tensor:Float[-1, 2, -1, -1]
name:546
tensor:Float[-1, 3, -1, -1]
项目
代码
using OpenCvSharp;
using System;
using System.Diagnostics;
using System.Drawing;
using System.Drawing.Imaging;
using System.Runtime.InteropServices;
using System.Text;
using System.Windows.Forms;
namespace DocumentUndistort
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
Stopwatch stopwatch = new Stopwatch();
Mat image;
Mat out_img;
string image_path;
string startupPath;
string fileFilter = "*.*|*.bmp;*.jpg;*.jpeg;*.tiff;*.tiff;*.png";
const string DllName = "DocumentUndistortSharp.dll";
IntPtr engine;
/*
//初始化
extern "C" _declspec(dllexport) int __cdecl init(void** engine, char* binary_model_path, char* unblur_model_path, char* unshadow_model_gcnet_path, char* unshadow_model_drnet_path, char* unwrap_model_path, char* msg);
//binary
extern "C" _declspec(dllexport) int __cdecl binary(void* engine, Mat* srcimg, char* msg, Mat* out_img);
//unblur
extern "C" _declspec(dllexport) int __cdecl unblur(void* engine, Mat* srcimg, char* msg, Mat* out_img);
//unshadow
extern "C" _declspec(dllexport) int __cdecl unshadow(void* engine, Mat* srcimg, char* msg, Mat* out_img);
//unwrap
extern "C" _declspec(dllexport) int __cdecl unwrap(void* engine, Mat* srcimg, char* msg, Mat* out_img);
//openCvBilateral
extern "C" _declspec(dllexport) int __cdecl openCvBilateral(Mat* srcimg, char* msg, Mat* out_img);
//释放
extern "C" _declspec(dllexport) void __cdecl destroy(void* engine);
*/
[DllImport(DllName, EntryPoint = "init", CallingConvention = CallingConvention.Cdecl)]
internal extern static int init(ref IntPtr engine, string binary_model_path, string unblur_model_path, string unshadow_model_gcnet_path, string unshadow_model_drnet_path, string unwrap_model_path, StringBuilder msg);
[DllImport(DllName, EntryPoint = "binary", CallingConvention = CallingConvention.Cdecl)]
internal extern static int binary(IntPtr engine, IntPtr srcimg, StringBuilder msg, IntPtr out_img);
[DllImport(DllName, EntryPoint = "unblur", CallingConvention = CallingConvention.Cdecl)]
internal extern static int unblur(IntPtr engine, IntPtr srcimg, StringBuilder msg, IntPtr out_img);
[DllImport(DllName, EntryPoint = "unshadow", CallingConvention = CallingConvention.Cdecl)]
internal extern static int unshadow(IntPtr engine, IntPtr srcimg, StringBuilder msg, IntPtr out_img);
[DllImport(DllName, EntryPoint = "unwrap", CallingConvention = CallingConvention.Cdecl)]
internal extern static int unwrap(IntPtr engine, IntPtr srcimg, StringBuilder msg, IntPtr out_img);
[DllImport(DllName, EntryPoint = "openCvBilateral", CallingConvention = CallingConvention.Cdecl)]
internal extern static int openCvBilateral(IntPtr srcimg, StringBuilder msg, IntPtr out_img);
[DllImport(DllName, EntryPoint = "destroy", CallingConvention = CallingConvention.Cdecl)]
internal extern static int destroy(IntPtr engine);
private void button1_Click(object sender, EventArgs e)
{
OpenFileDialog ofd = new OpenFileDialog();
ofd.Filter = fileFilter;
if (ofd.ShowDialog() != DialogResult.OK) return;
pictureBox1.Image = null;
pictureBox2.Image = null;
textBox1.Text = "";
image_path = ofd.FileName;
pictureBox1.Image = new Bitmap(image_path);
image = new Mat(image_path);
}
private void Form1_Load(object sender, EventArgs e)
{
startupPath = Application.StartupPath;
string binary_model_path = startupPath + "\\model\\unetcnn.onnx";
string unblur_model_path = startupPath + "\\model\\nafdpm.onnx";
string unshadow_model_gcnet_path = startupPath + "\\model\\gcnet.onnx";
string unshadow_model_drnet_path = startupPath + "\\model\\drnet.onnx";
string unwrap_model_path = startupPath + "\\model\\uvdoc.onnx";
StringBuilder msg = new StringBuilder(512);
int res = init(ref engine, binary_model_path, unblur_model_path, unshadow_model_gcnet_path, unshadow_model_drnet_path, unwrap_model_path, msg);
if (res == -1)
{
MessageBox.Show(msg.ToString());
return;
}
else
{
Console.WriteLine(msg.ToString());
}
image_path = startupPath + "\\test_img\\2.jpg";
pictureBox1.Image = new Bitmap(image_path);
image = new Mat(image_path);
}
private void Form1_FormClosed(object sender, FormClosedEventArgs e)
{
destroy(engine);
}
/// <summary>
/// unwrap
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void button2_Click(object sender, EventArgs e)
{
if (image_path == "")
{
return;
}
textBox1.Text = "执行中......";
Application.DoEvents();
if (image != null) image.Dispose();
if (out_img != null) out_img.Dispose();
if (pictureBox1.Image != null) pictureBox1.Image.Dispose();
StringBuilder msg = new StringBuilder(512);
image = new Mat(image_path);
out_img = new Mat();
stopwatch.Restart();
int res = unwrap(engine, image.CvPtr, msg, out_img.CvPtr);
if (res == 0)
{
stopwatch.Stop();
double costTime = stopwatch.Elapsed.TotalMilliseconds;
pictureBox2.Image = new Bitmap(out_img.ToMemoryStream());
textBox1.Text = $"耗时:{costTime:F2}ms";
}
else
{
textBox1.Text = "失败," + msg.ToString();
}
}
/// <summary>
/// openCvBilateral
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void button7_Click(object sender, EventArgs e)
{
if (image_path == "")
{
return;
}
textBox1.Text = "执行中......";
Application.DoEvents();
if (image != null) image.Dispose();
if (out_img != null) out_img.Dispose();
if (pictureBox1.Image != null) pictureBox1.Image.Dispose();
StringBuilder msg = new StringBuilder(512);
image = new Mat(image_path);
out_img = new Mat();
stopwatch.Restart();
int res = openCvBilateral(image.CvPtr, msg, out_img.CvPtr);
if (res == 0)
{
stopwatch.Stop();
double costTime = stopwatch.Elapsed.TotalMilliseconds;
pictureBox2.Image = new Bitmap(out_img.ToMemoryStream());
textBox1.Text = $"耗时:{costTime:F2}ms";
}
else
{
textBox1.Text = "失败," + msg.ToString();
}
}
/// <summary>
/// unshadow
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void button6_Click(object sender, EventArgs e)
{
if (image_path == "")
{
return;
}
textBox1.Text = "执行中......";
Application.DoEvents();
if (image != null) image.Dispose();
if (out_img != null) out_img.Dispose();
if (pictureBox1.Image != null) pictureBox1.Image.Dispose();
StringBuilder msg = new StringBuilder(512);
image = new Mat(image_path);
out_img = new Mat();
stopwatch.Restart();
int res = unshadow(engine, image.CvPtr, msg, out_img.CvPtr);
if (res == 0)
{
stopwatch.Stop();
double costTime = stopwatch.Elapsed.TotalMilliseconds;
pictureBox2.Image = new Bitmap(out_img.ToMemoryStream());
textBox1.Text = $"耗时:{costTime:F2}ms";
}
else
{
textBox1.Text = "失败," + msg.ToString();
}
}
/// <summary>
/// unblur
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void button5_Click(object sender, EventArgs e)
{
if (image_path == "")
{
return;
}
textBox1.Text = "执行中......";
Application.DoEvents();
if (image != null) image.Dispose();
if (out_img != null) out_img.Dispose();
if (pictureBox1.Image != null) pictureBox1.Image.Dispose();
StringBuilder msg = new StringBuilder(512);
image = new Mat(image_path);
out_img = new Mat();
stopwatch.Restart();
int res = unblur(engine, image.CvPtr, msg, out_img.CvPtr);
if (res == 0)
{
stopwatch.Stop();
double costTime = stopwatch.Elapsed.TotalMilliseconds;
pictureBox2.Image = new Bitmap(out_img.ToMemoryStream());
textBox1.Text = $"耗时:{costTime:F2}ms";
}
else
{
textBox1.Text = "失败," + msg.ToString();
}
}
/// <summary>
/// binary
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void button4_Click(object sender, EventArgs e)
{
if (image_path == "")
{
return;
}
textBox1.Text = "执行中......";
Application.DoEvents();
if (image != null) image.Dispose();
if (out_img != null) out_img.Dispose();
if (pictureBox1.Image != null) pictureBox1.Image.Dispose();
StringBuilder msg = new StringBuilder(512);
image = new Mat(image_path);
out_img = new Mat();
stopwatch.Restart();
int res = binary(engine, image.CvPtr, msg, out_img.CvPtr);
if (res == 0)
{
stopwatch.Stop();
double costTime = stopwatch.Elapsed.TotalMilliseconds;
pictureBox2.Image = new Bitmap(out_img.ToMemoryStream());
textBox1.Text = $"耗时:{costTime:F2}ms";
}
else
{
textBox1.Text = "失败," + msg.ToString();
}
}
private void button3_Click(object sender, EventArgs e)
{
if (pictureBox2.Image == null)
{
return;
}
Bitmap output = new Bitmap(pictureBox2.Image);
var sdf = new SaveFileDialog();
sdf.Title = "保存";
sdf.Filter = "Images (*.jpg)|*.jpg|Images (*.png)|*.png|Images (*.bmp)|*.bmp";
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;
}
}
MessageBox.Show("保存成功,位置:" + sdf.FileName);
}
}
}
}
using OpenCvSharp;
using System;
using System.Diagnostics;
using System.Drawing;
using System.Drawing.Imaging;
using System.Runtime.InteropServices;
using System.Text;
using System.Windows.Forms;
namespace DocumentUndistort
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
Stopwatch stopwatch = new Stopwatch();
Mat image;
Mat out_img;
string image_path;
string startupPath;
string fileFilter = "*.*|*.bmp;*.jpg;*.jpeg;*.tiff;*.tiff;*.png";
const string DllName = "DocumentUndistortSharp.dll";
IntPtr engine;
/*
//初始化
extern "C" _declspec(dllexport) int __cdecl init(void** engine, char* binary_model_path, char* unblur_model_path, char* unshadow_model_gcnet_path, char* unshadow_model_drnet_path, char* unwrap_model_path, char* msg);
//binary
extern "C" _declspec(dllexport) int __cdecl binary(void* engine, Mat* srcimg, char* msg, Mat* out_img);
//unblur
extern "C" _declspec(dllexport) int __cdecl unblur(void* engine, Mat* srcimg, char* msg, Mat* out_img);
//unshadow
extern "C" _declspec(dllexport) int __cdecl unshadow(void* engine, Mat* srcimg, char* msg, Mat* out_img);
//unwrap
extern "C" _declspec(dllexport) int __cdecl unwrap(void* engine, Mat* srcimg, char* msg, Mat* out_img);
//openCvBilateral
extern "C" _declspec(dllexport) int __cdecl openCvBilateral(Mat* srcimg, char* msg, Mat* out_img);
//释放
extern "C" _declspec(dllexport) void __cdecl destroy(void* engine);
*/
[DllImport(DllName, EntryPoint = "init", CallingConvention = CallingConvention.Cdecl)]
internal extern static int init(ref IntPtr engine, string binary_model_path, string unblur_model_path, string unshadow_model_gcnet_path, string unshadow_model_drnet_path, string unwrap_model_path, StringBuilder msg);
[DllImport(DllName, EntryPoint = "binary", CallingConvention = CallingConvention.Cdecl)]
internal extern static int binary(IntPtr engine, IntPtr srcimg, StringBuilder msg, IntPtr out_img);
[DllImport(DllName, EntryPoint = "unblur", CallingConvention = CallingConvention.Cdecl)]
internal extern static int unblur(IntPtr engine, IntPtr srcimg, StringBuilder msg, IntPtr out_img);
[DllImport(DllName, EntryPoint = "unshadow", CallingConvention = CallingConvention.Cdecl)]
internal extern static int unshadow(IntPtr engine, IntPtr srcimg, StringBuilder msg, IntPtr out_img);
[DllImport(DllName, EntryPoint = "unwrap", CallingConvention = CallingConvention.Cdecl)]
internal extern static int unwrap(IntPtr engine, IntPtr srcimg, StringBuilder msg, IntPtr out_img);
[DllImport(DllName, EntryPoint = "openCvBilateral", CallingConvention = CallingConvention.Cdecl)]
internal extern static int openCvBilateral(IntPtr srcimg, StringBuilder msg, IntPtr out_img);
[DllImport(DllName, EntryPoint = "destroy", CallingConvention = CallingConvention.Cdecl)]
internal extern static int destroy(IntPtr engine);
private void button1_Click(object sender, EventArgs e)
{
OpenFileDialog ofd = new OpenFileDialog();
ofd.Filter = fileFilter;
if (ofd.ShowDialog() != DialogResult.OK) return;
pictureBox1.Image = null;
pictureBox2.Image = null;
textBox1.Text = "";
image_path = ofd.FileName;
pictureBox1.Image = new Bitmap(image_path);
image = new Mat(image_path);
}
private void Form1_Load(object sender, EventArgs e)
{
startupPath = Application.StartupPath;
string binary_model_path = startupPath + "\\model\\unetcnn.onnx";
string unblur_model_path = startupPath + "\\model\\nafdpm.onnx";
string unshadow_model_gcnet_path = startupPath + "\\model\\gcnet.onnx";
string unshadow_model_drnet_path = startupPath + "\\model\\drnet.onnx";
string unwrap_model_path = startupPath + "\\model\\uvdoc.onnx";
StringBuilder msg = new StringBuilder(512);
int res = init(ref engine, binary_model_path, unblur_model_path, unshadow_model_gcnet_path, unshadow_model_drnet_path, unwrap_model_path, msg);
if (res == -1)
{
MessageBox.Show(msg.ToString());
return;
}
else
{
Console.WriteLine(msg.ToString());
}
image_path = startupPath + "\\test_img\\2.jpg";
pictureBox1.Image = new Bitmap(image_path);
image = new Mat(image_path);
}
private void Form1_FormClosed(object sender, FormClosedEventArgs e)
{
destroy(engine);
}
/// <summary>
/// unwrap
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void button2_Click(object sender, EventArgs e)
{
if (image_path == "")
{
return;
}
textBox1.Text = "执行中......";
Application.DoEvents();
if (image != null) image.Dispose();
if (out_img != null) out_img.Dispose();
if (pictureBox1.Image != null) pictureBox1.Image.Dispose();
StringBuilder msg = new StringBuilder(512);
image = new Mat(image_path);
out_img = new Mat();
stopwatch.Restart();
int res = unwrap(engine, image.CvPtr, msg, out_img.CvPtr);
if (res == 0)
{
stopwatch.Stop();
double costTime = stopwatch.Elapsed.TotalMilliseconds;
pictureBox2.Image = new Bitmap(out_img.ToMemoryStream());
textBox1.Text = $"耗时:{costTime:F2}ms";
}
else
{
textBox1.Text = "失败," + msg.ToString();
}
}
/// <summary>
/// openCvBilateral
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void button7_Click(object sender, EventArgs e)
{
if (image_path == "")
{
return;
}
textBox1.Text = "执行中......";
Application.DoEvents();
if (image != null) image.Dispose();
if (out_img != null) out_img.Dispose();
if (pictureBox1.Image != null) pictureBox1.Image.Dispose();
StringBuilder msg = new StringBuilder(512);
image = new Mat(image_path);
out_img = new Mat();
stopwatch.Restart();
int res = openCvBilateral(image.CvPtr, msg, out_img.CvPtr);
if (res == 0)
{
stopwatch.Stop();
double costTime = stopwatch.Elapsed.TotalMilliseconds;
pictureBox2.Image = new Bitmap(out_img.ToMemoryStream());
textBox1.Text = $"耗时:{costTime:F2}ms";
}
else
{
textBox1.Text = "失败," + msg.ToString();
}
}
/// <summary>
/// unshadow
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void button6_Click(object sender, EventArgs e)
{
if (image_path == "")
{
return;
}
textBox1.Text = "执行中......";
Application.DoEvents();
if (image != null) image.Dispose();
if (out_img != null) out_img.Dispose();
if (pictureBox1.Image != null) pictureBox1.Image.Dispose();
StringBuilder msg = new StringBuilder(512);
image = new Mat(image_path);
out_img = new Mat();
stopwatch.Restart();
int res = unshadow(engine, image.CvPtr, msg, out_img.CvPtr);
if (res == 0)
{
stopwatch.Stop();
double costTime = stopwatch.Elapsed.TotalMilliseconds;
pictureBox2.Image = new Bitmap(out_img.ToMemoryStream());
textBox1.Text = $"耗时:{costTime:F2}ms";
}
else
{
textBox1.Text = "失败," + msg.ToString();
}
}
/// <summary>
/// unblur
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void button5_Click(object sender, EventArgs e)
{
if (image_path == "")
{
return;
}
textBox1.Text = "执行中......";
Application.DoEvents();
if (image != null) image.Dispose();
if (out_img != null) out_img.Dispose();
if (pictureBox1.Image != null) pictureBox1.Image.Dispose();
StringBuilder msg = new StringBuilder(512);
image = new Mat(image_path);
out_img = new Mat();
stopwatch.Restart();
int res = unblur(engine, image.CvPtr, msg, out_img.CvPtr);
if (res == 0)
{
stopwatch.Stop();
double costTime = stopwatch.Elapsed.TotalMilliseconds;
pictureBox2.Image = new Bitmap(out_img.ToMemoryStream());
textBox1.Text = $"耗时:{costTime:F2}ms";
}
else
{
textBox1.Text = "失败," + msg.ToString();
}
}
/// <summary>
/// binary
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void button4_Click(object sender, EventArgs e)
{
if (image_path == "")
{
return;
}
textBox1.Text = "执行中......";
Application.DoEvents();
if (image != null) image.Dispose();
if (out_img != null) out_img.Dispose();
if (pictureBox1.Image != null) pictureBox1.Image.Dispose();
StringBuilder msg = new StringBuilder(512);
image = new Mat(image_path);
out_img = new Mat();
stopwatch.Restart();
int res = binary(engine, image.CvPtr, msg, out_img.CvPtr);
if (res == 0)
{
stopwatch.Stop();
double costTime = stopwatch.Elapsed.TotalMilliseconds;
pictureBox2.Image = new Bitmap(out_img.ToMemoryStream());
textBox1.Text = $"耗时:{costTime:F2}ms";
}
else
{
textBox1.Text = "失败," + msg.ToString();
}
}
private void button3_Click(object sender, EventArgs e)
{
if (pictureBox2.Image == null)
{
return;
}
Bitmap output = new Bitmap(pictureBox2.Image);
var sdf = new SaveFileDialog();
sdf.Title = "保存";
sdf.Filter = "Images (*.jpg)|*.jpg|Images (*.png)|*.png|Images (*.bmp)|*.bmp";
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;
}
}
MessageBox.Show("保存成功,位置:" + sdf.FileName);
}
}
}
}