OpenCvSharp for Network

OpenCV 2021. 12. 28. 22:45 |
반응형

C#에서 OpenCV Mat 데이터를 네트워크로 송수신 할 수 있도록 준비하는 과정을 시뮬레이션 해 보자.

아래 링크의 글에서 비트맵이 아닌 OpenCV Mat 데이터 송수신 과정이라 보면 된다.

2021.12.25 - [C#] - C# TCP/IP Image transfer - 이미지(파일) 전송 3

 

폼에 PictureBox, Button을 적당히 배치한다.

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
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 OpenCvSharp;
using System.IO;
 
namespace OpenCV
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
 
            pictureBox1.SizeMode = PictureBoxSizeMode.StretchImage;
        }
 
        private void button1_Click(object sender, EventArgs e)
        {
            // 클라이언트 시뮬레이션
            // OpenCV Matrix를 생성하고 바이트 배열로 변환한다.
            Mat clientImage = new Mat("Barbara.jpg");
            byte[] data = clientImage.ToBytes(".jpg"); // ".jpg", ".png", ".bmp"
            //MemoryStream clientMemoryStream = clientImage.ToMemoryStream();
            //byte[] data = clientMemoryStream.ToArray();
 
            // 네트워크 시뮬레이션
            // ...
            // 클라이언트에서 OpenCV Matrix 바이트 배열(data)을 서버로 전송
 
            // 서버 시뮬레이션
            // 클라이언트에서 받은 바이트 배열(data)을 메모리 스트림으로
            // 변환 후 다시 비트맵으로 변환한다.
            MemoryStream serverMemoryStream = new MemoryStream(data);
            Bitmap bitmap = new Bitmap(serverMemoryStream);
            //Mat serverImage = OpenCvSharp.Extensions.BitmapConverter.ToMat(bitmap);
            //Cv2.ImShow("Server Image", serverImage);
            pictureBox1.Image = bitmap;
        }
    }
}
 

 

클라이언트에서 Mat.ToBytes()가 핵심이다. (메모리 스트림으로 변환할 필요가 없다)

소스를 입력하고 빌드한다.

 

실행하면 버튼만 나타난다.

 

버튼을 클릭하면 이미지가 표시된다.

 

반응형
Posted by J-sean
:

OpenCV with C#

OpenCV 2021. 11. 20. 10:22 |
반응형

C#으로 OpenCV를 사용해 보자.

 

새로운 프로젝트를 만든다.

 

C# - Windows - Desktop - Windows Forms App (.NET Framework)

 

적당한 이름과 위치를 지정한다.

 

Tools - Nuget Package Manager - Manage Nuget Packages for Solution...

 

 

Browse - OpenCV를 검색하고 OpenCvSharp4.Windows by shimat 선택, 오른쪽 창에서 현재 프로젝트(OpenCV)를 선택하고 Install을 클릭한다.

 

OK를 클릭한다.

 

설치가 완료되면 폼에 Button과 Picture Box를 하나씩 배치한다.

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
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 OpenCvSharp;
 
namespace OpenCV
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }
 
        private void button1_Click(object sender, EventArgs e)
        {
            try
            {
                OpenFileDialog dlg = new OpenFileDialog();
                if (dlg.ShowDialog() == DialogResult.OK)
                {
                    Mat mat = Cv2.ImRead(dlg.FileName);
 
                    if (pictureBox1.Image != null)
                    {
                        pictureBox1.Image.Dispose();
                    }
 
                    // Mat to Bitmap 1
                    //Bitmap bitmap = new Bitmap(mat.ToMemoryStream());
                    //pictureBox1.Image = bitmap;
 
                    // Mat to Bitmap 2
                    //Bitmap bitmap = (Bitmap)Image.FromStream(mat.ToMemoryStream());
                    //pictureBox1.Image = bitmap;
 
                    // Mat to Bitmap 3
                    System.IO.MemoryStream memoryStream = new System.IO.MemoryStream(mat.ToBytes());
                    pictureBox1.Image = new Bitmap(memoryStream);
                }
            }
            catch (Exception exc)
            {
                MessageBox.Show(exc.Message);
            }
        }
    }
}
 

 

OpenCvSharp를 using 선언하고 버튼 클릭 이벤트 핸들러를 작성한다.

 

 

실행하고 버튼을 클릭해 적당한 그래픽 파일을 선택한다.

 

 

※ 참고

1. 인터넷 사용이 불가능한 컴퓨터라면 아래 링크에서 release된 dll 파일을 다운받고 직접 reference에 추가하여 사용하면 된다.

OpenCvSharp

 

2. API 레퍼런스

OpenCvSharp API Reference

 

반응형
Posted by J-sean
:
반응형

Linux가 아닌 Windows에서는 Microsoft Visual C++을 사용하는 경우가 많다. 아래 링크와 같이 Qt를 설치한다.

2021.09.25 - [C, C++] - Qt6 설치 및 간단한 사용법

 

Qt Widgets Application 프로젝트를 생성하고 프로젝트명.pro 파일을 확인한다.

 

프로젝트명.pro 파일을 위와 같이 수정한다. (opencv는 C:\opencv에 설치되어 있다)

CONFIG(debug, debug|release) {
    LIBS += -lopencv_world453d
}

CONFIG(release, debug|release) {
    LIBS += -lopencv_world453
}

opencv_world453은 C:\opencv\build\x64\vc15\bin 폴더의 opencv_worldXXX.dll, opencv_worldXXXd.dll 파일을 참고해 작성한다.

 

Projects - Build & Run - Run - Environment - Path 에 C:\opencv\build\x64\vc15\bin을 추가한다.

 

UI Design에서 Pushbutton을 하나 추가하고 우클릭 - Go to slot...을 클릭한다.

 

 

clicked()를 선택한다.

 

on_pushButton_clicked()를 위와 같이 수정한다. (상단에 opencv.hpp가 include 되어있다)

 

프로젝트를 빌드하고 XXX-Debug 폴더에 사진 파일을 복사한다.

 

실행하면 위와 같은 위도우가 나타난다. PushButton을 클릭하자.

 

 

Barbara palvin 사진이 출력된다.

 

반응형
Posted by J-sean
:
반응형

리눅스(우분투)에서 OpenCV 이미지(cv::Mat)를 Qt로(QImage::QImage) 디스플레이 해 보자.

(cv::Mat ↔  QImage::QImage)

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
#include <QApplication>
#include <QWidget>
#include <QPainter>
#include <opencv2/opencv.hpp>
 
class Picture : public QWidget
{
public:
    Picture(QWidget* parent = 0);
    ~Picture();
 
protected:
    void paintEvent(QPaintEvent* event);
    // This event handler can be reimplemented in a subclass to receive paint events passed in event.
    void drawPicture(QPainter* qp);
    QImage Mat2QImage(cv::Mat const& src);
    cv::Mat QImage2Mat(QImage const& src);
 
private:
    int height;
    int width;
    QImage qtImage;
    cv::Mat cvImage;
};
 
Picture::Picture(QWidget* parent) : QWidget(parent)
{
    //image.load("Barbara Palvin.png");
    //cvimage = QImage2Mat(image);
 
    //Read images from OpenCV. Not from Qt.
    cvImage = cv::imread("Barbara Palvin.png", cv::IMREAD_COLOR);
    if (cvImage.empty())
    {
        std::cerr << "Image load failed." << std::endl;
 
        exit(EXIT_FAILURE);
    }
 
    cv::Mat tempCvImage;
    cv::cvtColor(cvImage, tempCvImage, cv::COLOR_RGB2GRAY);
 
    qtImage = Mat2QImage(tempCvImage);
    tempCvImage = QImage2Mat(qtImage);
 
    cv::resize(tempCvImage, tempCvImage, cv::Size(), 1.51.5);
    cv::imshow("OpenCV", tempCvImage);
 
    height = qtImage.height();
    width = qtImage.width();
 
    this->resize(width, height);
}
 
Picture::~Picture()
{
 
}
 
void Picture::paintEvent(QPaintEvent* e)
{
    Q_UNUSED(e);
    // Q_UNUSED( name)
    // Indicates to the compiler that the parameter with the specified name is not used in the body
    // of a function. This can be used to suppress compiler warnings while allowing functions to be
    // defined with meaningful parameter names in their signatures.
 
    QPainter qp(this);
    drawPicture(&qp);
}
 
void Picture::drawPicture(QPainter* qp)
{
    qp->drawImage(00, qtImage);
}
 
QImage Picture::Mat2QImage(cv::Mat const& src)
{
    cv::Mat temp;
    cv::cvtColor(src, temp, cv::COLOR_BGR2RGB);
    QImage dest((const uchar*)temp.data, temp.cols, temp.rows, temp.step, QImage::Format_RGB888);
    dest.bits();
    // Enforce deep copy
    // See documentation of QImage::QImage (const uchar * data, int width, int height, Format format)
 
    return dest;
}
 
cv::Mat Picture::QImage2Mat(QImage const& src)
{
    cv::Mat temp(src.height(), src.width(), CV_8UC3, (uchar*)src.bits(), src.bytesPerLine());
    cv::Mat result; // Deep copy
    cv::cvtColor(temp, result, cv::COLOR_BGR2RGB);
 
    return result;
}
 
int main(int argc, char* argv[])
{
    QApplication app(argc, argv);
 
    Picture window;
    window.setWindowTitle("Qt");
    //window.resize(width, height);
 
    window.show();
 
    return app.exec();
}
 
 

 

소스를 입력한다. (qtcv.cpp)

 

컴파일(빌드)하고 실행하면 cv::imshow(), QPainter::drawImage() 모두 잘 표시된다. (OpenCV는 50% 확대)

 

반응형
Posted by J-sean
:
반응형

It describes how to detect faces with Haar-cascade classifier.

OpenCV에서 Haar-cascade classifier를 이용한 얼굴 검출.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
#include <opencv2/opencv.hpp>
 
using namespace std;
using namespace cv;
 
int main()
{
    Mat src = imread("girl.jpg");
 
    if (src.empty()) {
        cerr << "Image load failed." << endl;
 
        return -1;
    }
 
    CascadeClassifier classifier("haarcascade_frontalface_default.xml");
    // Cascade classifier class for object detection.
 
    if (classifier.empty()) {
        cerr << "Classifier load failed." << endl;
 
        return -1;
    }
 
    vector<Rect> faces;
    classifier.detectMultiScale(src, faces);
    // Detects objects of different sizes in the input image.
    // The detected objects are returned as a list of rectangles.
 
    for (Rect rect : faces) {
        rectangle(src, rect, Scalar(00255), 2);
    }
 
    imshow("Face Detection", src);
 
    waitKey(0);
 
    return 0;
}



Run the program and see the result.


Detected two babies' faces.


It couldn't detect a face with shades and detected some wrong objects.


반응형
Posted by J-sean
:
반응형

It shows how to detect and decode a QR Code.

OpenCV에서 QR코드를 감지하고 내용을 확인할 수 있다.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
#include <Windows.h>
#include <opencv2/opencv.hpp>
 
using namespace std;
using namespace cv;
 
int main()
{
    VideoCapture cap(0);
 
    if (!cap.isOpened()) {
        cerr << "Camera open failed." << endl;
 
        return -1;
    }
 
    QRCodeDetector detector;
 
    Mat frame;
    vector<Point> points;
    String msg;
 
    while (true) {
        cap >> frame;
 
        if (frame.empty()) {
            cerr << "Empty frame." << endl;
 
            break;
        }
 
        msg = detector.detectAndDecode(frame, points); // Both detects and decodes QR code.
 
        if (!msg.empty()) {
            polylines(frame, points, true, Scalar(00255), 2);
            putText(frame, msg, Point(1030), FONT_HERSHEY_PLAIN, 2, Scalar(00255), 2);
 
            if (msg.substr(04== "http") {
                imshow("QR Code", frame);
 
                if (MessageBox(NULL, (msg + " is a website address.\nDo you want to visit?").c_str(), "QR Code", MB_YESNO) == IDYES) {
                    ShellExecute(NULL"open", msg.c_str(), NULLNULL, SW_SHOW);
                    // Performs an operation on a specified file.
                }
                else {
                    continue;
                }
            }
        }
        else {
            putText(frame, "No QR code detected", Point(1030), FONT_HERSHEY_PLAIN, 2, Scalar(00255), 2);
        }
 
        imshow("QR Code", frame);
 
        if (waitKey(10== 27)
            break;
    }
 
    return 0;
}



Run the program. It says 'No QR code detected' at first.


QR code with a message.


QR code with a website address.


If the first 4 letters of the message are 'http', it opens the website with the default web browser.



반응형
Posted by J-sean
:
반응형

Hue is the color portion of the model, expressed as a number from 0 to 360 degrees:

Red: falls between 0 and 60 degrees.

Yellow: falls between 61 and 120 degrees.

Green: falls between 121-180 degrees.

Cyan: falls between 181-240 degrees.

Blue: falls between 241-300 degrees.

Magenta: falls between 301-360 degrees.


For HSV, OpenCV Hue range is [0,179], Saturation range is [0,255] and Value range is [0,255]. Different software uses different scales. So if you are comparing OpenCV values with them, you need to normalize these ranges.


HSV(Hue)를 이용하면 RGB를 이용하는 것 보다 간단히 특정색을 검출할 수 있다. OpenCV의 Hue값은 0~179 이다.



1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
#include <opencv2/opencv.hpp>
 
using namespace std;
using namespace cv;
 
int lowerHue = 40, upperHue = 80;    // Green
Mat src, src_hsv, mask, dst;
 
void OnHueChenaged(int pos, void* userdata)
{
    Scalar lowerb(lowerHue, 1000);
    Scalar upperb(upperHue, 255255);
 
    inRange(src_hsv, lowerb, upperb, mask);
    // Checks if array elements lie between the elements of two other arrays.
 
    dst.setTo(0);    // 매번 초기화 해 주지 않으면 이전에 선택한 색과 겹친다.
    src.copyTo(dst, mask);
    // The method copies the matrix data to another matrix. Before copying the data, the method invokes: m.create(this->size(), this->type());
    // so that the destination matrix is reallocated if needed.While m.copyTo(m); works flawlessly, the function does not handle the case of a
    // partial overlap between the sourceand the destination matrices. When the operation mask is specified, if the Mat::create call shown above
    // reallocates the matrix, the newly allocated matrix is initialized with all zeros before copying the data.
 
    imshow("mask", mask);
    imshow("dst", dst);
}
 
int main(int argc, char** argv)
{
    src = imread("candies.jpg", IMREAD_COLOR);
    if (src.empty()) {
        cerr << "Image load failed." << endl;
        
        return -1;
    }
 
    imshow("src", src);
 
    cvtColor(src, src_hsv, COLOR_BGR2HSV);
 
    namedWindow("mask");
    createTrackbar("Lower Hue""mask"&lowerHue, 179, OnHueChenaged);
    createTrackbar("Upper Hue""mask"&upperHue, 179, OnHueChenaged);
    OnHueChenaged(NULLNULL);
 
    waitKey(0);
    
    return 0;
}




Original candy image.


Mask for green color.


Green candies detected.


반응형
Posted by J-sean
:
반응형

This is a Windows backend only function but you can simply copy or save the image displayed with cv::imshow().


cv::imshow()로 이미지를 출력할 때 출력된 이미지를 간단히 클립 보드에 복사하거나 파일로 저장 할 수 있다.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#include <opencv2/opencv.hpp>
 
using namespace std;
using namespace cv;
 
int main(int argc, char** argv)
{
    Mat src = imread("matera.jpg");
    if (src.empty()) {
        cerr << "Image load failed." << endl;
 
        return 0;
    }
 
    imshow("src", src);
    
    waitKey(0);
    
    return 0;
}



[Windows backend only]

  • Pressing Ctrl+C will copy the image to the clipboard.
  • Pressing Ctrl+S will show a dialog to save the image




반응형
Posted by J-sean
: