博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
为基于OpenCV的图像处理程序编写界面—关于QT\MFC\CSharp的选择以及GOCW的介绍
阅读量:5131 次
发布时间:2019-06-13

本文共 5689 字,大约阅读时间需要 18 分钟。

        基于OpenCV编写图像处理项目,除了算法以外,比较重要一个问题就是界面设计问题。对于c++语系的程序员来说,一般来说有QT/MFC两种考虑。QT的确功能强大,特别是QML编写android界面很有一套( ),在树莓派上进行设计也很方便( );但是使用QT的一个现实问题就是和现有平台的结合,比如客户需要将结果导出到excel中,使用QT就比较别扭(当然不是说不可以)。所以现在我一般这样来做:对于Android和PI,或者需要在Linux上运行的项目,使用QT编写界面,调用Opencv函数;对于需要在windows上运行的项目,使用MFC编写界面,直接就可以引用OpenCV。
        有人会吐槽MFC使用起来非常麻烦,这点我非常同意。但MFC经过这么多年的发展,今日仍有活力,并且短时间内不会消失。因为相比较其他一些所见即所得的语言和环境来说(QT/Csharp),mfc的消息映射机制和坐标体系等,的确有它的优势,对于图像处理程序来说尤其如此;加以积累,能够快速做出很多专业的东西;近期出现的ribbon界面也为mfc加分不少( )
       选择了MFC这个方向,思考图像处理程序问题,一般来说分为“处理图像”和"处理视频"两类:对于图像处理来说,我提供的GOPaint框架( )能够提供一个基本的静态图像处理框架;而GOMFCTemplate2( )则适合用来处理视频。这两种都
分别成功运用于多种视频处理项目中。
       但是这里我想更进一步:希望能够用Csharp编写界面,因为它更好用;但是又不想引入EmguCV类似的库,因为里面很多东西不是我需要的。那么最直接的方法就是使用Csharp调用基于Opencv编写的类库文件(Dll)的,我取名叫做
       经过比较长时间的探索研究,目前的GOCW已经可以直接以函数的形式在内存中传递bitmap和Mat对象,达到了函数级别的应用。因为这里涉及到托管代码编写,也就是CLR程序编写,所以有比较复杂的地方;为了展现GOCW的优良特性,我编写实现GOGPY项目,也就是一个"Csharp编写界面,OpenCV实现算法的实时视频处理程序”,相关细节都包含其中。之所以叫“GPY”,是采集硬件这块,我采用了成像质量较好的高拍仪设备(GaoPaiYi)。
       这里简单将最核心内容进行讲解。GOCW的核心问题,无非就是基于CLR之上的两个方向的数据流转换。核心函数为
Bitmap
^  GOClrClass
:
:testMethod(cli
:
:array
<
unsigned 
char
>
^ pCBuf1)
{
    pin_ptr
<System
:
:Byte
> p1 
= 
&pCBuf1[
0];
    
unsigned 
char
* pby1 
= p1;
    cv
:
:Mat img_data1(pCBuf1
-
>Length,
1,CV_8U,pby1);
    cv
:
:Mat img_object 
= cv
:
:imdecode(img_data1,IMREAD_UNCHANGED);
//获得数据到img_object中去
    
//处理过程///
    cvtColor(img_object,img_object,
40);
    
    
/
    Bitmap
^ bb 
= MatToBitmap(img_object);
    
if (
!img_object.data)
        
return nullptr;
    std
:
:vector
<uchar
> buf;
    cv
:
:imencode(
".jpg", img_object, buf);
    
return bb;
}
以及
System
:
:Drawing
:
:Bitmap
^ MatToBitmap(
const cv
:
:Mat
& img)
{
    
if (img.type() 
!= CV_8UC3)
    {
        
throw gcnew NotSupportedException(
"Only images of type CV_8UC3 are supported for conversion to Bitmap");
    }
    
//create the bitmap and get the pointer to the data
    PixelFormat fmt(PixelFormat
:
:Format24bppRgb);
    Bitmap 
^bmpimg 
= gcnew Bitmap(img.cols, img.rows, fmt);
    BitmapData 
^data 
= bmpimg
-
>LockBits(System
:
:Drawing
:
:Rectangle(
0
0, img.cols, img.rows), ImageLockMode
:
:WriteOnly, fmt);
    
//byte *dstData = reinterpret_cast<byte*>(data->Scan0.ToPointer());
    Byte 
*dstData 
= 
reinterpret_cast
<Byte
*
>(data
-
>Scan0.ToPointer());
    
unsigned 
char 
*srcData 
= img.data;
    
for (
int row 
= 
0; row 
< data
-
>Height; 
++row)
    {
        memcpy(
reinterpret_cast
<
void
*
>(
&dstData[row
*data
-
>Stride]), 
reinterpret_cast
<
void
*
>(
&srcData[row
*img.step]), img.cols
*img.channels());
    }
    bmpimg
-
>UnlockBits(data);
    
return bmpimg;
}
 
而在chsarp中,直接
Bitmap b
=
new Bitmap(cam.Width, cam.Height, cam.Stride, PixelFormat.Format24bppRgb, m_ip);
// If the image is upsidedown
b.RotateFlip(RotateFlipType.RotateNoneFlipY);
srcImage
= b;
if (picPreview.Image
!= null)
    picPreview.Image.Dispose();
//调用clr+opencv图像处理模块
MemoryStream ms
=
new MemoryStream();
b.Save(ms, System.Drawing.Imaging.ImageFormat.Jpeg);
byte[] bytes
= ms.GetBuffer();
Bitmap bitmap
= client.testMethod(bytes);
就可以调用,并且获得结果。
 
以下内容为2017年更新的内容,适当参考:
一、CLR编写的DLL部分
1、按照正常方法引入Opencv;
2、提供接口函数,进行图像处理(这里只是实现了cvtColor,实际过程中可以用自己编写的复杂函数)
String
^  Class1
:
:Method(cli
:
:array
<
unsigned 
char
>
^ pCBuf1)
{
     pin_ptr
<System
:
:Byte
> p1 
= 
&pCBuf1[
0];
     
unsigned 
char
* pby1 
= p1;
     cv
:
:Mat img_data1(pCBuf1
-
>Length,
1,CV_8U,pby1);
     cv
:
:Mat img_object 
= cv
:
:imdecode(img_data1,IMREAD_UNCHANGED);
     
//处理过程/
     cvtColor(img_object,img_object,
40);
     
/
     
if (
!img_object.data)
        
return nullptr;
     
//获得目录,保存文件
     cv
:
:imwrite(
"c:/Method.jpg",img_object);
     
return 
"c:/Method.jpg";
}
 
String
^  Class1
:
:Method2(cli
:
:array
<
unsigned 
char
>
^ pCBuf1)
{
    pin_ptr
<System
:
:Byte
> p1 
= 
&pCBuf1[
0];
    
unsigned 
char
* pby1 
= p1;
    cv
:
:Mat img_data1(pCBuf1
-
>Length,
1,CV_8U,pby1);
    cv
:
:Mat img_object 
= cv
:
:imdecode(img_data1,IMREAD_UNCHANGED);
    
//处理过程///
    cvtColor(img_object,img_object,
6);
 
/
    
if (
!img_object.data)
        
return nullptr;
    
//获得目录,保存文件
    cv
:
:imwrite(
"c:/Method2.jpg",img_object);
    
return 
"c:/Method2.jpg";
}
二、Winform调用接口部分(TIP:不仅可以用Winform调用,asp.net/webservice都是可以调用的)
1、直接引用clr dll
2、编写helper文件(应该也可以叫做 warpper),通过外部IO的方法获取clr dll的文件
 
class GOCsharpHelper
    {
        Class1 client 
= 
new Class1();
        string strResult1 
= null;
        string strResult2 
= null;
        
//输入参数是string或bitmap
        
public Bitmap ImageProcess(string ImagePath){
            Image  ImageTemp 
= Bitmap.FromFile(ImagePath);
            
return ImageProcess(ImageTemp);
        }
        
//输出结果是bitmap
        
public Bitmap ImageProcess(Image image)
        {
            MemoryStream ms 
= 
new MemoryStream();
            image.Save(ms, System.Drawing.Imaging.ImageFormat.Jpeg);
            byte[] bytes 
= ms.GetBuffer();
            strResult1 
= client.Method(bytes);
            Image ImageResult 
= Bitmap.FromFile(strResult1);
            
return (Bitmap)ImageResult;
        }
        
public Bitmap ImageProcess2(string ImagePath)
        {
            Image ImageTemp 
= Bitmap.FromFile(ImagePath);
            
return ImageProcess2(ImageTemp);
        }
        
//输出结果是bitmap
        
public Bitmap ImageProcess2(Image image)
        {
            MemoryStream ms 
= 
new MemoryStream();
            image.Save(ms, System.Drawing.Imaging.ImageFormat.Jpeg);
            byte[] bytes 
= ms.GetBuffer();
            strResult2 
= client.Method2(bytes);
            Image ImageResult 
= Bitmap.FromFile(strResult2);
            
return (Bitmap)ImageResult;
        }
        
public 
void Clear()
        {
            
if (File.Exists(strResult1))
                File.Delete(strResult1);
            
if (File.Exists(strResult2))
                File.Delete(strResult2);
        }
    }
3、使用例子(注意控件的dispose):
 
   
private 
void button2_Click(object sender, EventArgs e)
        {
            
if (pictureBox1.Image 
!= null)
                pictureBox1.Image.Dispose();
            
if (pictureBox2.Image 
!= null)
                pictureBox2.Image.Dispose();
           Image image1 
= gocsharphelper.ImageProcess(
" E:/sandbox/logo.jpg");
           pictureBox1.Image 
= image1;
           Image image2 
= gocsharphelper.ImageProcess2(
"E:/sandbox/lena.jpg");
           pictureBox2.Image 
= image2;
         
        }
 
三、解释说明 
使用外部I/O不仅仅是权宜之计,实际上Opencv的Decode使用的就是外部I/O。就目前研究的水平来说,这是最稳定的。
目前搭建成功的框架已经能够完成“csharp调用opencv的”目标,并且在调试、参数传递方面都很强。
如果是处理静态图片,已经够用。
四、杀手程序
GOImageResearch:
使用这种方法编写的图像处理预分析程序。

转载于:https://www.cnblogs.com/jsxyhelu/p/9509181.html

你可能感兴趣的文章
LibSVM for Python 使用
查看>>
入坑的开始~O(∩_∩)O~
查看>>
Centos 7.0 安装Mono 3.4 和 Jexus 5.6
查看>>
Windows 7 上安装Visual Studio 2015 失败解决方案
查看>>
iOS按钮长按
查看>>
Shell流程控制
查看>>
CSS属性值currentColor
查看>>
[Leetcode|SQL] Combine Two Tables
查看>>
《DSP using MATLAB》Problem 7.37
查看>>
ROS lesson 1
查看>>
js笔记
查看>>
c风格字符串函数
查看>>
python基础学习第二天
查看>>
java可重入锁reentrantlock
查看>>
浅谈卷积神经网络及matlab实现
查看>>
struts2学习(9)struts标签2(界面标签、其他标签)
查看>>
Android 导入jar包 so模块--导入放置的目录
查看>>
解决ajax请求cors跨域问题
查看>>
Android Studio
查看>>
zz 圣诞丨太阁所有的免费算法视频资料整理
查看>>