基於OpenCV實現“鋼管計數”算法,基於Csharp編寫界面,並實現算法融合【完成】


一、DL現狀、本例范疇
本例顯然屬於object localization。
二、支撐環境和基本流程
這個基本上來說,就是采用百度自己提供的數據集(后期我這個桌面食物數據集也上傳)和工具來做了。非常值得注意一點的是百度的標注工具,有智能標准的能力。我沒有全部標注完,但是結果已經非常不錯。

首先是創建這個數據集。我采用“高拍儀拍攝3個松鼠食物”的方法來進行。共采集45張圖片,其中訓練的40張要有部分是比較難以識別的,檢測的5張相對質量較好。

這種小規模的數據集那是相當棒的結果了。

數據集訓練好了,其實我更關心的是調用問題,好像Csharp有接口的,我來看看;其實對於以下任何一種方式來說,調用都是問題:


充10塊錢就可以了
使用之前的Csharp代碼來進行調用實驗。

這里的購買方式都是可選的,我認為這種方式未來肯定是很好的,但是要考慮消費者習慣;此外,本地OpenCV調用方式,肯定是需要的;還有公網這種調用方式,還需要研究研究才能夠實現的。     
直接提供了H5的調用方式,在采集方式不統一的情況下給出較高結果,使得我認為這可能就是最后需要采用的方法。

三、GOCW的引入
      希望能夠用Csharp編寫界面,因為它更好用;但是又不想引入EmguCV類似的庫,因為里面很多東西不是我需要的。那么最直接的方法就是使用Csharp調用基於Opencv編寫的類庫文件(Dll)的,我取名叫做GreenOpenCsharpWarper(GOCW)
       經過比較長時間的探索研究,目前的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( 00, 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;
}
 
而在csharp中,直接
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);
就可以調用,並且獲得結果。

 
四、本例的實現、訓練和效果
4.1、重構解決方案
GOCVhelper做算法研究和函數封裝;GOImage做dll;Csharp程序開發界面;
解決OpenCV版本問題,進行函數封裝。
現在環境配置已經精簡
此外將.dll拷貝到能夠被訪問的地方就可以。
下一步在保證效果不變的情況下,進行函數封裝。OK可行;
4.2、GOCW封裝
采用輸入圖片是Mat直接輸入;輸出結果還是ini外部存儲的方式,最為有效。
因為有良好的積累,所以很快就完成了基本算法移植
但是這還不夠,有兩個界面操作,1個是框選、一個是圓的產生和去除。其中框選需要結合QML一起來想,圓操作現在應該可行。
很快算法集成成功,主要還是得益於之前的有效積累。
這里還有一個升級版本

基於GOCW的界面,成功打通EasyDL通道
private void button4_Click(object senderEventArgs e)
        {
            //保存json
            List<Dictionary<Stringfloat>> listDic = new List<Dictionary<Stringfloat>>();
            for (int i=0;i<listCenter.Count;i++)
            {
                PointF pointf = listCenter[i];
                Dictionary<Stringfloatdic = new Dictionary<Stringfloat>()
                {
                      { "name",99999},
                      { "x1",(pointf.X-3)},
                      { "y1",(pointf.Y-3)},
                      { "x2",(pointf.X+3)},
                      { "y2",(pointf.Y+3)}
                };
                listDic.Add(dic);
            }
            String Jsondata = JsonConvert.SerializeObject(listDic);
            Jsondata =  Jsondata.Replace("99999.0""\"pip\"");
            Jsondata = "{\"labels\": " + Jsondata + "}";
            StreamWriter writer = new StreamWriter(strFliePath.TrimEnd(".jpg".ToArray())+"_.json"false);
            writer.Write(Jsondata);
            writer.Close();
            //在原目錄保存縮放后的img
            bmpCrop.Save(strFliePath.TrimEnd(".jpg".ToArray()) + "_.jpg");
        }
其中這段:
  StreamWriter   writer  =  new   StreamWriter ( strFliePath . TrimEnd ( ".jpg" . ToArray ())+ "_.json" false );
編碼格式,卡了我一晚上。
最后通過比較工具才發現了編碼不同。
要不斷有計划地誰用過新工具
4.3在線訓練、觀察調參



方法應該是可行的,但是訓練的過程肯定是需要系統方法。在沒有足夠標注數據的情況下,必須首先研究自動標注方法。

五、小結

1、Csharp編寫界面非常重要,是核心能力。但是目前標注仍然是很困難,需要3-5min一幅圖;
2、什么樣的特征需要標注?需要標注到什么程度?這些都是值得研究的,需要長期思考的工程問題;
3、建立用戶參與的標注采集機制,是最終需要的,我們如何建立這個機制,關鍵是第一參與者的參與;
4、EasyDL是非常棒的BaseLine,它肯定不止采用了YOLO,它的效果是非常重要的參考;此外“智能標注”模式也值得參考。





附件列表

     


    免責聲明!

    本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



     
    粵ICP備18138465號   © 2018-2025 CODEPRJ.COM