請先參考下面這一篇, 建立所需的編譯環境

RGB顏色範圍內的遮罩應用 Part I: Visual Studio 2013編譯環境建構

-------------------------------------------------------

1. 先建立一個可以接收C# UI丟過來的影像檔案的路徑名稱 imread(filename)

2. 利用imshow()顯示影像

新增一個header file

image

滑鼠點選Header File(.h)

輸入檔名: colorInRange.h

image

General->Common Language Runtime Support

image

colorInRange.h

#include <wchar.h>
#include <opencv2\highgui\highgui.hpp>
#include <opencv2\imgproc\imgproc.hpp>
 
#pragma once
 
namespace CVision
{
    public ref class ImgProc
    {
    public:
        bool imread(wchar_t* filename);     
        bool imshow();
        ImgProc();
        ~ImgProc();
 
    private:
        std::string WstringToString(const std::wstring str);
    };
 
    ImgProc::ImgProc()
    {
    }
 
    ImgProc::~ImgProc()
    {
    }
 
 
}

colorInRange.cpp

// colorInRange.cpp : Defines the exported functions for the DLL application.
//
 
#include "stdafx.h"
#include "colorInRange.h"
 
using namespace std;
using namespace cv;
 
namespace CVision
{
    string m_filename;
    Mat m_src;
 
    bool ImgProc::imread(wchar_t* filename)
    {
        wstring ws(filename);
 
        m_filename = ImgProc::WstringToString(ws);
        m_src = cv::imread(m_filename);
        if (!m_src.data)
            return false;
        else
            return true;
 
    }
 
    bool ImgProc::imshow()
    {
        if (!m_src.data)
            return -1;
 
        // Show source image
        namedWindow("Source Image", CV_WINDOW_NORMAL);
        cv::imshow("Source Image", m_src);
        return 0;
    }
 
 
    std::string ImgProc::WstringToString(const std::wstring str)
    {
        unsigned len = str.size() * 4;
        setlocale(LC_CTYPE, "cht");
        char *p = new char[len];
        wcstombs(p, str.c_str(), len);
        std::string str1(p);
        delete[] p;
        return str1;
    }
}

Preprocessor加入_CRT_SECURE_NO_WARNINGS [4]

image

測試編譯DLL, 如果成功的話可以產出一個colorInRange.dll

E:\opencv\prog\colorInRange\x64\Debug

image

----------------------------------------------------

接下來, 撰寫C# UI客戶端

image

專案類型: Visual C# Windows Forms Application

專案名稱: colorInRangeClient

image

加入參考 colorInRange.dll

image

瀏覽E:\opencv\prog\colorInRange\x64\Debug\colorInRange.dll

image

image

image

專案Build

Allow unsafe code

image

Form1.cs

開啟一張圖檔並顯示影像

C# UI用到C++ DLL定義的兩個方法:imread()和imshow()

在C#只需要下列步驟

1. using namespace CVsion

2. 宣告 ImgProc 變數 m_ip;

3. 給定該變數實體化 m_ip = new ImgProc();

4. 透過OpenFileDialog取得照片的檔案路徑,

5. m_ip.imread(filename): 讓m_ip物件得到檔案路徑

6. m_ip.imshow():   m_ip物件 顯示影像

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using CVision;
 
namespace colorInRangeClient
{
    public partial class Form1 : Form
    {
        ImgProc m_ip;
        public Form1()
        {
            InitializeComponent();
            m_ip = new ImgProc();
        }
 
        private void openToolStripMenuItem_Click(object sender, EventArgs e)
        {
            using(OpenFileDialog ofd = new OpenFileDialog())
            {
                if (ofd.ShowDialog() == System.Windows.Forms.DialogResult.OK)
                {
                    unsafe
                    {
                        fixed (char* filename = ofd.FileName)
                        {
                            m_ip.imread(filename);
                        }
                        m_ip.imshow();
                    }
                    this.Text = ofd.FileName;
                }
            }    
        }
    }
}

image

下載範例1: colorInRange beta version

-------------------------------------------------------

接下來, 節錄原作者的問題

I would like to detect a red colored object in a video or image, with OpenCV and C++. What algorithms are available to do this?

I would like to do a comparison of the relationship between levels of color. Indeed, when the brightness varies, the ratio remains constant. So I want to determine the interval of acceptable values ​​for the colors of zone of interest.

For cases I look at the red R (x, y) and G (x, y) / R (x, y) and B (x, y) / R (x, y).

I will then find the ranges of acceptable values​​: to get a first idea, it releases the maximum and minimum for each report from a palette image red

I would like to find something like this :

if minR<=R(x,y)<=maxR and minG<=G(x,y)<=maxG minB<=B(x,y)<=maxB so couleur(x,y)=blanc else couleur(x,y)=NOIR

-------------------------------------------------------

以下是被接受的回答

Preprocess the image using cv::inRange() with the necessary color bounds to isolate red. You may want to transform to a color-space like HSV or YCbCr for more stable color bounds because chrominance and luminance are better separated. You can use cvtColor() for this. Check out my answer here for a good example of using  with inRange() with createTrackBar(). So, the basic template would be:

Mat redColorOnly;
inRange(src, Scalar(lowBlue, lowGreen, lowRed), Scalar(highBlue, highGreen, highRed), redColorOnly);
detectSquares(redColorOnly);

EDIT : Just use the trackbars to determine the color range you want to isolate, and then use the color intervals you find that work. You don't have to constantly use the trackbars.

EXAMPLE :
So, for a complete example of the template here you go,

I created a simple (and ideal) image in GIMP, shown below: enter image description here

Then I created this program to filter all but the red squares:

#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include <iostream>

using namespace std;
using namespace cv;

Mat redFilter(const Mat& src)
{
    assert(src.type() == CV_8UC3);

    Mat redOnly;
    inRange(src, Scalar(0, 0, 0), Scalar(0, 0, 255), redOnly);

    return redOnly;
}

int main(int argc, char** argv)
{
    Mat input = imread("colored_squares.png");

    imshow("input", input);
    waitKey();

    Mat redOnly = redFilter(input);

    imshow("redOnly", redOnly);
    waitKey();

    // detect squares after filtering...

    return 0;
}

NOTE : You will not be able to use these exact same filter intervals for your real imagery; I just suggest you tune the intervals with trackbars to see what is acceptable.

The output looks like this:

enter image description here

-------------------------------------------------------

接下來, 先更新UI的功能, minR<=R(x,y)<=maxR and minG<=G(x,y)<=maxG minB<=B(x,y)<=maxB

每次更新參數得到一張新的遮罩(顏色範圍內為白色, 顏色範圍外的為黑色, 如上圖所示)

所以會需要提供R, G, B的上下限的水平卷軸, 並將參數傳給C++ DLL,

image

回到C++ 專案, 編輯顏色範圍內的函式

colorInRange.h

 
#include <wchar.h>
#include <opencv2\highgui\highgui.hpp>
#include <opencv2\imgproc\imgproc.hpp>
 
#pragma once
 
using namespace std;
using namespace cv;
 
namespace CVision
{
    public ref class ImgProc
    {
    public:
        void runColorInRangeRGB(UINT minR, UINT maxR, UINT minG, UINT maxG, UINT minB, UINT maxB);                // 執行RGB顏色範圍內像素
        bool imread(wchar_t* filename);     
        bool imshow();
        ImgProc();
        ~ImgProc();
 
    private:
        Mat colorInRangeRGB(const Mat& src, UINT minR, UINT maxR, UINT minG, UINT maxG, UINT minB, UINT maxB);    // 篩選RGB顏色範圍內像素
        std::string WstringToString(const std::wstring str);
    };
 
    ImgProc::ImgProc()
    {
    }
 
    ImgProc::~ImgProc()
    {
    }
 
 
}

colorInRange.cpp

// colorInRange.cpp : Defines the exported functions for the DLL application.
//
 
#include "stdafx.h"
#include "colorInRange.h"
 
 
 
namespace CVision
{
    string m_filename;
    Mat m_src;
 
    bool ImgProc::imread(wchar_t* filename)
    {
        wstring ws(filename);
 
        m_filename = ImgProc::WstringToString(ws);
        m_src = cv::imread(m_filename);
        if (!m_src.data)
            return false;
        else
            return true;
 
    }
 
    bool ImgProc::imshow()
    {
        if (!m_src.data)
            return -1;
 
        // Show source image
        namedWindow("Source Image", CV_WINDOW_NORMAL);
        cv::imshow("Source Image", m_src);
        return 0;
    }
    
    // 篩選RGB顏色範圍內像素
    Mat ImgProc::colorInRangeRGB(const Mat& src, UINT minR, UINT maxR, UINT minG, UINT maxG, UINT minB, UINT maxB)
    {
        assert(src.type() == CV_8UC3);
        Mat mask;
        inRange(src, Scalar(minB, minG, minR), Scalar(maxB, maxG, maxR), mask);
        return mask;
    }
    // 執行RGB顏色範圍內像素
    void ImgProc::runColorInRangeRGB(UINT minR, UINT maxR, UINT minG, UINT maxG, UINT minB, UINT maxB)
    {
        Mat mask = colorInRangeRGB(m_src, minR, maxR, minG, maxG, minB, maxB);
        if (!mask.data)
            return;
 
        // Show source image
        namedWindow("color in range of RGB", CV_WINDOW_NORMAL);
        cv::imshow("color in range of RGB", mask);
    }
 
    std::string ImgProc::WstringToString(const std::wstring str)
    {
        unsigned len = str.size() * 4;
        setlocale(LC_CTYPE, "cht");
        char *p = new char[len];
        wcstombs(p, str.c_str(), len);
        std::string str1(p);
        delete[] p;
        return str1;
    }
}
 

回到colorInRangeClient C# Windows Form, 準備加入ImgProc->RGB in range回覆函式

image

呼叫剛才新增的函式runColorInRangeRGB()

image

private void rGBToolStripMenuItem_Click(object sender, EventArgs e)
{
    uint minR, maxR, minG, maxG, minB, maxB;
    uint.TryParse(numericUpDown1.Value.ToString(), out minR);
    uint.TryParse(numericUpDown2.Value.ToString(), out maxR);
    uint.TryParse(numericUpDown3.Value.ToString(), out minG);
    uint.TryParse(numericUpDown4.Value.ToString(), out maxG);
    uint.TryParse(numericUpDown5.Value.ToString(), out minB);
    uint.TryParse(numericUpDown6.Value.ToString(), out maxB);
    m_ip.runColorInRangeRGB(minR, maxR, minG, maxG, minB, maxB);
}

接著refactor 上述的callback function

image

製作成一個Method, 方便其他按鈕呼叫

image

修改後如下

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using CVision;
 
namespace colorInRangeClient
{
    public partial class Form1 : Form
    {
        ImgProc m_ip;
        public Form1()
        {
            InitializeComponent();
            m_ip = new ImgProc();
        }
 
        private void openToolStripMenuItem_Click(object sender, EventArgs e)
        {
            using(OpenFileDialog ofd = new OpenFileDialog())
            {
                if (ofd.ShowDialog() == System.Windows.Forms.DialogResult.OK)
                {
                    unsafe
                    {
                        fixed (char* filename = ofd.FileName)
                        {
                            m_ip.imread(filename);
                        }
                        m_ip.imshow();
                    }
                    this.Text = ofd.FileName;
                }
            }    
        }
 
        private void rGBToolStripMenuItem_Click(object sender, EventArgs e)
        {
            runColorInRangeRGB();
        }
 
        private void runColorInRangeRGB()
        {
            uint minR, maxR, minG, maxG, minB, maxB;
            uint.TryParse(numericUpDown1.Value.ToString(), out minR);
            uint.TryParse(numericUpDown2.Value.ToString(), out maxR);
            uint.TryParse(numericUpDown3.Value.ToString(), out minG);
            uint.TryParse(numericUpDown4.Value.ToString(), out maxG);
            uint.TryParse(numericUpDown5.Value.ToString(), out minB);
            uint.TryParse(numericUpDown6.Value.ToString(), out maxB);
            m_ip.runColorInRangeRGB(minR, maxR, minG, maxG, minB, maxB);
        }
 
        private void numericUpDown1_ValueChanged(object sender, EventArgs e)
        {
            runColorInRangeRGB();
        }
 
        private void numericUpDown2_ValueChanged(object sender, EventArgs e)
        {
            runColorInRangeRGB();
        }
 
        private void numericUpDown3_ValueChanged(object sender, EventArgs e)
        {
            runColorInRangeRGB();
        }
 
        private void numericUpDown4_ValueChanged(object sender, EventArgs e)
        {
            runColorInRangeRGB();
        }
 
        private void numericUpDown5_ValueChanged(object sender, EventArgs e)
        {
            runColorInRangeRGB();
        }
 
        private void numericUpDown6_ValueChanged(object sender, EventArgs e)
        {
            runColorInRangeRGB();
        }
    }
}

測試結果

image

image

image

image

image

下載範例2: colorInRange ver2

參考資料:

1. Quick Installation for OpenCV 2.4.10 with Visual Studio 2013

2. 利用C# 拉UI並傳參數給OpenCV C++ DLL

3. Detect RGB color interval with OpenCV and C++

4. Remove secure warnings (_CRT_SECURE_NO_WARNINGS) from projects by default in Visual Studio

arrow
arrow
    全站熱搜
    創作者介紹
    創作者 me1237guy 的頭像
    me1237guy

    天天向上

    me1237guy 發表在 痞客邦 留言(0) 人氣()