C# OpenCvSharp 部署文档矫正,包括文档扭曲/模糊/阴影等情况

目录

说明

效果

模型

项目

代码

下载

参考


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);
            }
        }
    }
}

下载

源码下载

参考

https://github.com/hpc203/document-undistort-onnxrun