IP Camera ONVIF Protocol

OpenCV 2025. 3. 1. 10:24 |
반응형

 

ONVIF 프로토콜을 지원하는 IP 카메라를 사용해 보자.

 

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
import cv2
 
#capture = cv2.VideoCapture(0, cv2.CAP_DSHOW)
# 노트북에 연결된 카메라는 대부분 cv2.CAP_DSHOW 옵션이 필요 없지만
# 데스크탑에 USB로 연결된 카메라 사용시에는 cv2.CAP_DSHOW 옵션이 필요 할 수 있다.
 
#cap = cv2.VideoCapture('rtsp://admin:@192.168.0.44')
# NVR 사용
 
cap = cv2.VideoCapture('rtsp://admin:123456@192.168.0.161:554/stream0')
# NVR 없이 카메라만 연결 Sub Stream
# 형식: rtsp://[ID]:[PW]@[IP주소]:[PORT번호]/[기타설정]
 
#cap = cv2.VideoCapture('rtsp://admin:123456@192.168.0.161:554/stream1')
# NVR 없이 카메라만 연결 Main Stream
 
# 카메라 Configure - Stream manager - Video Setting - Encoding Format 에서
# H265 로 설정하면 아래와 같은 에러 메세지가 발생한다.
# [hevc @ 0000024133eada80] PPS id out of range: 0
# H264 로 설정하면 괜찮다.
 
if not cap.isOpened():
    print("Not opened")
    exit()
 
while cv2.waitKey(1< 0:
    ret, frame = cap.read()
    if not ret:
        print("False returned")
        exit()
    cv2.imshow("video", frame)
 
cap.release()
cv2.destroyAllWindows()
 

 

만약 Sub Stream(Stream0)이 아닌 Main Stream(Stream1)을 사용하면 영상은 큰 문제 없이 계속 출력되지만 아래와 같은 에러 메세지가 계속 나타난다. (Sub Stream에서도 종종 에러가 발생하기도 했다)

 

 

이런 에러 때문인지는 모르겠지만 OpenCV에서 rtsp를 이용해 출력한 영상은 카메라에서 자체 지원하는 웹뷰 등을 이용해 확인한 영상보다 노이즈가 심하다.

 

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
import queue
import threading
import cv2
 
q=queue.Queue()
stop = False
 
def Receive():
    print("start Reveiving")
    
    cap = cv2.VideoCapture('rtsp://admin:123456@192.168.0.161:554/stream0')
    if not cap.isOpened():
        print("Not opened")
        exit()
    
    global stop
    ret = True
    while ret and not stop:
        ret, frame = cap.read()
        lock.acquire()
        if not ret:
            print("False returned")
            continue
        q.put(frame)
        lock.release()
    
    cap.release()
    cv2.destroyAllWindows()
 
def Display():
     print("Start Displaying")
 
     global stop
     while cv2.waitKey(1< 0:
         lock.acquire()
         if not q.empty():
             frame=q.get()
             cv2.imshow("stream", frame)
         lock.release()
     stop = True
 
if __name__ == '__main__':
    lock = threading.Lock()
    
    t1 = threading.Thread(target = Receive)
    t2 = threading.Thread(target = Display)
    t1.start()
   t2.start()
 

 

영상을 받아오는 부분과 출력하는 부분을 다른 스레드로 구분하고 각각의 스레드에서 영상에 접근할때 충돌을 방지하기 위해 Primitive Lock을 사용해 봤지만 별 효과는 없다.

오히려 Main Stream(Stream1)에서 Sub Stream(Stream0)으로 바꿔 영상의 크기를 줄이는게 에러 확률을 크게 낮추었다.

 

 

카메라 Video Setting 에서 위와 같이 바꾸는 것도 에러 확률을 크게 낮추었다.

● Resolution: 1920X1080 => 1280X720

● Quality: Good => Worst 

Frame Rate, Max Bitrate는 별 영향이 없었다.

 

Packet Loss가 있어서 그런건지도 모르겠다.

stackoverflow

 

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

C와 Python 프로그램간 이미지 데이터를 공유해 보자.

 

1) 파이썬 프로그램 데이터를 C 프로그램에 공유

mmap

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
import time
import mmap
import cv2
 
frame = cv2.imread("image.jpg", cv2.IMREAD_COLOR)
h, w, c = frame.shape
buffer_size = h * w * c
 
mm = mmap.mmap(-1, buffer_size, "Local\\MySharedMemory")
 
try:
    mm.write(frame.tobytes())
 
    while True:
        time.sleep(1000)  # Sleep to prevent busy waiting.
finally:
    mm.close()
 

 

 

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>
#include <Windows.h>
 
int main() {
    int height = 495;
    int width = 396;
    int channels = 3;
    int buffersize = height * width * channels;
 
    byte* buffer = new byte[buffersize];
    memset(buffer, 0, buffersize);
 
    HANDLE hFMap = CreateFileMapping(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0, buffersize, L"MySharedMemory");
    if (hFMap == NULL)
        return -1;
 
    TCHAR* PtrInFile = (TCHAR*)MapViewOfFile(hFMap, FILE_MAP_ALL_ACCESS, 00, buffersize);
    if (PtrInFile == NULL)
        return -1;
 
    memcpy(buffer, PtrInFile, buffersize);
 
    cv::Mat image = cv::Mat(height, width, CV_8UC3, buffer);
    if (image.empty())
        return -1;
 
    // 사용할 Mat이 이미 존재한다면 아래처럼 memcpy()를 사용할 수도 있다.
    //cv::Mat image(height, width, CV_8UC3); // 이미 존재하는 Mat
    //memcpy(image.data, buffer, buffersize); // buffer 사용하지 않고 메모리에서 image.data로 직접 복사해도 된다.
 
    cv::imshow("image", image);
    cv::waitKey(0);
        
    UnmapViewOfFile(PtrInFile);
    CloseHandle(hFMap);
    delete[] buffer;
 
    return 0;
}
 

 

 

파이썬 프로그램을 먼저 실행하고 C 프로그램을 실행한다.

 

 

2) C 프로그램 데이터를 파이썬 프로그램에 공유

 

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
#include <opencv2/opencv.hpp>
#include <Windows.h>
 
int main() {
    cv::Mat image = cv::imread("image.jpg");
    if (image.empty())
        return -1;
 
    int height = image.rows;
    int width = image.cols;
    int channels = image.channels();
    int buffersize = height * width * channels;
 
    HANDLE hFMap = CreateFileMapping(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0, buffersize, L"MySharedMemory");
    if (hFMap == NULL)
        return -1;
 
    TCHAR* PtrInFile = (TCHAR*)MapViewOfFile(hFMap, FILE_MAP_ALL_ACCESS, 00, buffersize);
    if (PtrInFile == NULL)
        return -1;
 
    memcpy(PtrInFile, image.data, buffersize);
    // 버퍼를 사용하지 않고 바로 메모리에 데이터 복사.
        
    int a;
    std::cin >> a;
    // 대기
 
    UnmapViewOfFile(PtrInFile);
    CloseHandle(hFMap);
    
    return 0;
}
 

 

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
import mmap
import numpy as np
import cv2
 
height = 495
width = 396
channels = 3
buffer_size = height * width * channels
 
mm = mmap.mmap(-1, buffer_size, "Local\\MySharedMemory")
 
try:    
    buffer = mm.read(buffer_size)
    image_arr = np.frombuffer(buffer, np.ubyte)
    image = image_arr.reshape(height, width, channels)
    
    cv2.imshow("image", image)
    cv2.waitKey(0)
finally:
    mm.close()
    cv2.destroyAllWindows()
 

 

결과는 같다.

 

※ 참고

2025.02.16 - [OpenCV] - C# and Python OpenCV Image Data Share (Memory Mapped File)

 

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

C#과 Python 프로그램간 이미지 데이터를 공유해 보자.

 

1) Python 프로그램 데이터를 C# 프로그램에 공유.

mmap

 

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
import time
import mmap
import cv2
 
frame = cv2.imread("image.jpg", cv2.IMREAD_COLOR)
h, w, c = frame.shape
buffer_size = h * w * c
 
# 3개의 4바이트(12바이트) 데이터를 위한 추가 공간 확보
#buffer_size = h * w * c + 12
 
# Open a memory-mapped file.
mm = mmap.mmap(-1, buffer_size, "Local\\MySharedMemory")
 
try:
    # 만약 3개의 4바이트 데이터를 저장하고 싶다면 아래와
    # 같이 한다.
    #mm.write(h.to_bytes(4))
    #mm.write(w.to_bytes(4))
    #mm.write(c.to_bytes(4))
 
    mm.write(frame.tobytes())
    
    # Keep the Python script running for demonstration.
    while True:
        time.sleep(1000)  # Sleep to prevent busy waiting.
finally:
    mm.close()
 

 

 

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
using OpenCvSharp;
using System.IO.MemoryMappedFiles;
using System.Runtime.InteropServices;
 
public class Program
{
    public static void Main()
    {
        int width = 396;
        int height = 495;
        int channels = 3;
 
        using (MemoryMappedFile mmf = MemoryMappedFile.OpenExisting("MySharedMemory"))
        {
            using (MemoryMappedViewAccessor accessor = mmf.CreateViewAccessor())
            {
                byte[] buffer = new byte[width * height * channels];
                accessor.ReadArray(0, buffer, 0, buffer.Length);
 
                // 만약 buffer 앞 부분에 3개의 4바이트 int 데이터가 저장되어 있다면 아래와 같이 읽는다.
                // (물론 위에서 buffer[] 생성시 12바이트의 추가 공간 확보가 필요하다)
                //int h = ((buffer[0] << 24) +  (buffer[1] << 16) + (buffer[2] << 8) + (buffer[3]));
                //Console.WriteLine(h);
                //int w = ((buffer[4] << 24) + (buffer[5] << 16) + (buffer[6] << 8) + (buffer[7]));
                //Console.WriteLine(w);
                //int c = ((buffer[8] << 24) + (buffer[9] << 16) + (buffer[10] << 8) + (buffer[11]));
                //Console.WriteLine(c);
 
                // When buffer[] represents encoded image data (ex. JPEG, PNG, etc.), you can use
                // FromImageData or ImDecode.
                //buffer = System.IO.File.ReadAllBytes("image.jpg");
                //Mat mat = Mat.FromImageData(buffer, ImreadModes.Color);                
                //Mat mat = Cv2.ImDecode(buffer, ImreadModes.Color);
 
                // When buffer[] represens pixel data (BGRBGR...) , you need to hard-code copying operation.
                //Mat mat = new Mat(height, width, MatType.CV_8UC3);
                //Mat.Indexer<Vec3b> indexer = mat.GetGenericIndexer<Vec3b>();
                //for (int y = 0; y < height; y++)
                //{
                //    for (int x = 0; x < width; x++)
                //    {
                //        int pos = y * width * channels + x * channels;
                //        byte blue = buffer[pos + 0];
                //        byte green = buffer[pos + 1];
                //        byte red = buffer[pos + 2];
                //        Vec3b newValue = new Vec3b(blue, green, red);
                //        indexer[y, x] = newValue;
                //    }
                //}
 
                // If buffer[]'s step length is equal to the Mat's, there is a more effective way.
                Mat mat = new Mat(height, width, MatType.CV_8UC3);
                int length = height * width * channels;
                Marshal.Copy(buffer, 0, mat.Data, length);
 
                Cv2.ImShow("image", mat);
                Cv2.WaitKey(0);
                Cv2.DestroyAllWindows();
            }
        }
    }
}
 

 

 

Python 프로그램을 먼저 실행하고 C# 프로그램을 실행한다.

 

2) C# 프로그램 데이터를 Python 프로그램에 공유.

 

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
using System;
using System.IO.MemoryMappedFiles;
using System.Runtime.InteropServices;
using OpenCvSharp;
 
public class Program
{
    public static void Main()
    {   
        Mat image = Cv2.ImRead("image.jpg", ImreadModes.Color);
        int width = image.Width;
        int height = image.Height;
        int channels = image.Channels();
        int buffer_size = width * height * channels;
 
        using (MemoryMappedFile mmf = MemoryMappedFile.CreateNew("MySharedMemory", buffer_size))
        {
            using (MemoryMappedViewAccessor accessor = mmf.CreateViewAccessor())
            {
                byte[] buffer = new byte[buffer_size];
                Marshal.Copy(image.Data, buffer, 0, buffer_size);
                accessor.WriteArray<byte>(0, buffer, 0, buffer_size);
            }
            
            Console.WriteLine("waiting...");
            Console.ReadLine();
        }        
    }
}
 

 

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
import mmap
import numpy as np
import cv2
 
height = 495
width = 396
channels = 3
buffer_size = height * width * channels
 
mm = mmap.mmap(-1, buffer_size, "Local\\MySharedMemory")
 
try:    
    buffer = mm.read(buffer_size)
    image_arr = np.frombuffer(buffer, np.ubyte)
    image = image_arr.reshape(height, width, channels)
    
    cv2.imshow("image", image)
    cv2.waitKey(0)
finally:
    mm.close()
    cv2.destroyAllWindows()
 

 

결과는 같다.

 

※ 참고

2025.02.23 - [OpenCV] - C and Python OpenCV Image Data Share (Memory Mapped File)

 

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

PyQt를 이용해 OpenCV 이미지를 출력해 보자.

 

디자이너에서 Dialog에 Label을 하나 배치하고 사이즈를 충분히 크게 한다. (test.ui)

 

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
import sys
import cv2
from PyQt5 import QtWidgets
from PyQt5 import QtGui
from PyQt5 import uic
 
myui = uic.loadUiType("test.ui")
 
class MyApp(QtWidgets.QWidget, myui[0]):
    def __init__(self):
        super().__init__()
        self.setupUi(self)
 
        # 1) QtWidgets.QGraphicsView()에 이미지 출력하기
        # pixmap = QtGui.QPixmap()
        # pixmap.load("palvin.jpg")
        # scene = QtWidgets.QGraphicsScene()
        # scene.addPixmap(pixmap)
        # self.graphicsView.setScene(scene)
 
        # 2) QtWidgets.QGraphicsView()에 OpenCV 이미지 출력하기
        # img = cv2.imread("palvin.jpg")
        # img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
        # h, w, c = img.shape
        # qimg = QtGui.QImage(img.data, w, h, w*c, QtGui.QImage.Format_RGB888)
        # pixmap = QtGui.QPixmap.fromImage(qimg)
        # scene = QtWidgets.QGraphicsScene()
        # scene.addPixmap(pixmap)
        # self.graphicsView.setScene(scene)
 
        # QtWidgets.Label에 OpenCV 이미지 출력하기
        img = cv2.imread("palvin.jpg")
        img = cv2.resize(img, (self.label.size().width(), self.label.size().height()))
        img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
        h, w, c = img.shape
        qimg = QtGui.QImage(img.data, w, h, w*c, QtGui.QImage.Format_RGB888)
        pixmap = QtGui.QPixmap.fromImage(qimg)
        self.label.setPixmap(pixmap)
 
if __name__ == "__main__":
    app = QtWidgets.QApplication(sys.argv)
    myWindow = MyApp()
    myWindow.show()
   app.exec_()
 

 

소스를 입력하고 실행한다.

 

Label 사이즈에 맞게 이미지가 조절되었다.

 

이번엔 GraphicsView를 사용해 보자. 위 소스에서 1번이나 2번 주석을 해제한다.

1, 2번 주석부분의 소스는 이미지 크기를 조절하지 않는다.

 

Label은 삭제하고 Graphics View를 배치하고 크기를 조정한다.

 

이미지가 Graphics View보다 크지만 스크롤바가 표시된다.

 

Widget 없이 Dialog에 직접 이미지를 출력할 수 도 있다. Dialog만 남기고 모두 삭제한다.

 

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
import sys
import cv2
from PyQt5 import QtWidgets
from PyQt5 import QtGui
from PyQt5 import uic
 
myui = uic.loadUiType("test.ui")
 
class MyApp(QtWidgets.QWidget, myui[0]):
    def __init__(self):
        super().__init__()
        self.setupUi(self)
 
        self.img = cv2.imread("palvin.jpg")        
        self.img = cv2.cvtColor(self.img, cv2.COLOR_BGR2RGB)
        h, w, c = self.img.shape
        h, w = int(h/6), int(w/6)        
        self.img = cv2.resize(self.img, (w, h))
        self.qimg = QtGui.QImage(self.img.data, w, h, w*c, QtGui.QImage.Format_RGB888)
    
    def paintEvent(self, e):
        qp = QtGui.QPainter(self)
        self.drawCVImage(qp)
 
    def drawCVImage(self, qp):
        qp.drawImage(1010self.qimg)
        
if __name__ == "__main__":
    app = QtWidgets.QApplication(sys.argv)
    myWindow = MyApp()
    myWindow.show()
   app.exec_()
 

 

소스를 입력하고 실행한다.

 

Dialog에 직접 이미지가 출력된다.

 

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

OpenPose 소스를 컴파일하고 실행해 보자.

 

CMake를 다운로드하고 설치한다.

 

CUDA Toolkit 11.1.1을 다운로드하고 설치한다.

 

권장옵션으로 설치한다.

 

cuDNN 8.1.0을 다운로드한다. (NVIDIA 로그인이 필요하다)

 

 

다운로드한 cuDNN 압축을 풀고 cuda 폴더를 위 경로에 복사한다.

 

적당한 디렉토리에 OpenPose를 클론한다.

 

git clone https://github.com/CMU-Perceptual-Computing-Lab/openpose

cd openpose

git submodule update --init --recursive --remote

 

build 폴더를 만든다.

 

CMake를 실행하고 경로를 설정한다. 그리고 Configure를 클릭한다.

 

 

위와 같이 설정하고 Finish를 클릭한다.

 

Configuring이 끝나면 Generate를 클릭한다.

Python이나 Unity에서 사용한다면 옵션을 선택한다.

(Configure에서 x64를 선택했다면 64비트 Python이 필요하다)

 

OpenPose.sln을 실행한다.

 

Solution Configurations를 Release로 바꾸고 빌드한다.

빌드가 완료되면 실행(Ctrl+F5)한다. OpenPoseDemo가 실행된다.

 

 

Visual Studio 외부에서 OpenPoseDemo.exe나 다른 예제를 실행하려면 아래 파일과 폴더를 같은 폴더에 복사해야 한다.

 

bin 폴더의 모든 파일을 실행파일이 있는 폴더에 복사한다.

 

models 폴더를 실행파일이 있는 폴더에 복사한다.

 

예제에 따라 examples 폴더가 필요할 수도 있다.

 

 

생각보다 메모리가 많이 필요하다.

 

※ 참고

OpenPose Installation

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

GDI Plus Bitmap을 OpenCV Mat으로, 다시 OpenCV Mat을 GDI Plus Bitmap으로 변환해 보자.

 

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
110
111
112
113
114
115
116
117
118
119
120
121
#include <windows.h>
#include <gdiplus.h>
#include <opencv2/opencv.hpp>
 
#pragma comment(lib, "gdiplus")
 
using namespace cv;
using namespace Gdiplus;
 
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
HINSTANCE g_hInst;
LPCSTR lpszClass = "Mat and Bitmap";
 
Mat originalImage;
Mat bitmapToMat;
 
int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpszCmdParam, int nCmdShow)
{
    HWND hWnd;
    MSG Message;
    WNDCLASS WndClass;
    g_hInst = hInstance;
 
    ULONG_PTR gpToken;
    GdiplusStartupInput gpsi;
    if (GdiplusStartup(&gpToken, &gpsi, NULL!= Ok) {
        MessageBox(NULL, TEXT("GDI+ start-up error."), TEXT("GDI+ Error"), MB_OK);
 
        return 0;
    }
 
    WndClass.cbClsExtra = 0;
    WndClass.cbWndExtra = 0;
    WndClass.hbrBackground = (HBRUSH)(COLOR_BTNFACE + 1); //(HBRUSH)GetStockObject(WHITE_BRUSH);
    WndClass.hCursor = LoadCursor(NULL, IDC_ARROW);
    WndClass.hIcon = LoadIcon(NULL, IDI_APPLICATION);
    WndClass.hInstance = hInstance;
    WndClass.lpfnWndProc = (WNDPROC)WndProc;
    WndClass.lpszClassName = lpszClass;
    WndClass.lpszMenuName = NULL;
    WndClass.style = CS_HREDRAW | CS_VREDRAW;
    RegisterClass(&WndClass);
 
    hWnd = CreateWindow(lpszClass, lpszClass, WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT,
        630960NULL, (HMENU)NULL, hInstance, NULL);
    ShowWindow(hWnd, nCmdShow);
 
    while (GetMessage(&Message, 000)) {
        TranslateMessage(&Message);
        DispatchMessage(&Message);
    }
 
    GdiplusShutdown(gpToken);
 
    return (int)Message.wParam;
}
 
Mat BitmapToMat(Bitmap* bitmap)
{
    PixelFormat pixelFormat = bitmap->GetPixelFormat();
    if (pixelFormat != PixelFormat32bppARGB) // PixelFormat24bppRGB
        return Mat();
 
    int width = bitmap->GetWidth();
    int height = bitmap->GetHeight();
    Gdiplus::Rect rectLock(00, width, height);
    Gdiplus::BitmapData bitmapData;
 
    if (bitmap->LockBits(&rectLock, Gdiplus::ImageLockModeRead, pixelFormat, &bitmapData) != Gdiplus::Ok)
        return Mat();
 
    Mat mat = Mat(height, width, CV_8UC4, // CV_8UC3
        static_cast<unsigned char*>(bitmapData.Scan0), bitmapData.Stride).clone();
 
    bitmap->UnlockBits(&bitmapData);
 
    return mat;
}
 
void OnPaint(HDC hdc)
{
    Graphics G(hdc);
 
    // Mat to Bitmap
    cvtColor(originalImage, originalImage, COLOR_BGR2BGRA);
    Bitmap bitmap((INT)originalImage.size().width, (INT)originalImage.size().height, (INT)originalImage.step,
        PixelFormat32bppARGB, originalImage.data);
    G.DrawImage(&bitmap, 00, bitmap.GetWidth(), bitmap.GetHeight());
 
    // Bitmap to Mat
    bitmapToMat = BitmapToMat(&bitmap);
 
    imshow("BitmapToMat", bitmapToMat);
}
 
LRESULT CALLBACK WndProc(HWND hWnd, UINT iMessage, WPARAM wParam, LPARAM lParam)
{
    HDC hdc;
    PAINTSTRUCT ps;
 
    switch (iMessage) {
    case WM_CREATE:
        originalImage = imread("Barbara.jpg");
 
        return 0;
 
    case WM_PAINT:
        hdc = BeginPaint(hWnd, &ps);
        OnPaint(hdc);
        EndPaint(hWnd, &ps);
 
        return 0;
 
    case WM_DESTROY:
        PostQuitMessage(0);
 
        return 0;
    }
 
    return(DefWindowProc(hWnd, iMessage, wParam, lParam));
}
 

 

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

 

실행하면 Bitmap과 Mat 포맷의 이미지가 출력된다.

 

Mat to Bitmap 주석 부분이 Mat에서 Bitmap으로 변환의 핵심이다.

 

위 함수가 Bitmap에서 Mat으로 변환의 핵심이다.

 

반응형

'OpenCV' 카테고리의 다른 글

OpenCV with Qt for Python(PyQt)  (0) 2025.02.09
Compiling and Running OpenPose from Source  (2) 2022.05.15
OpenCV with C# and Camera  (0) 2021.12.29
OpenCvSharp for Network  (0) 2021.12.28
OpenCV with C#  (0) 2021.11.20
Posted by J-sean
:

OpenCV with C# and Camera

OpenCV 2021. 12. 29. 17:32 |
반응형

C#으로 OpenCV와 카메라를 사용해 보자.

 

C#에서 OpenCV를 사용하기 위한 준비는 아래 링크를 참고 한다.

2021.11.20 - [OpenCV] - OpenCV with C#

 

하지만 링크와 같이 OpenCvSharp4.Windows만 설치하면 Extensions가 설치 되지 않으므로 마찬가지로 NuGet Package Manager에서 검색하고 설치한다. (BitmapConverter.ToBitmap()을 사용하기 위해)

 

OpenCvSharp4.Extensions를 설치한다.

 

폼에 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
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
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 System.Threading;
using OpenCvSharp;
using OpenCvSharp.Extensions;
 
namespace OpenCV
{
    public partial class Form1 : Form
    {
        bool isCameraOn;
 
        Thread thread;
        Mat mat;
        VideoCapture videoCapture;
 
        public Form1()
        {
            InitializeComponent();
 
            pictureBox1.SizeMode = PictureBoxSizeMode.StretchImage;
            button1.Text = "Start";
            isCameraOn = false;
        }
 
        private void CameraCallback()
        {
            mat = new Mat();
            videoCapture = new VideoCapture(0);
 
            if (!videoCapture.IsOpened())
            {
                Text = "Camera open failed!";
                return;
            }
 
            while (true)
            {
                videoCapture.Read(mat);
 
                if (!mat.Empty())
                {
                    pictureBox1.Image = BitmapConverter.ToBitmap(mat);
 
                    //System.IO.MemoryStream memoryStream = new System.IO.MemoryStream(mat.ToBytes());
                    //pictureBox1.Image = new Bitmap(memoryStream);
                }
            }
        }
 
        private void button1_Click(object sender, EventArgs e)
        {
            if (isCameraOn == false)
            {
                thread = new Thread(new ThreadStart(CameraCallback));
 
                thread.Start();
                isCameraOn = true;
                button1.Text = "Stop";
            }
            else
            {
                if (videoCapture.IsOpened())
                {
                    thread.Abort();
                    videoCapture.Release();
                    mat.Release();
                }
                isCameraOn = false;
                button1.Text = "Start";
            }
        }
 
        private void Form1_FormClosing(object sender, FormClosingEventArgs e)
        {
            if (thread != null && thread.IsAlive && videoCapture.IsOpened())
            {
                thread.Abort();
                videoCapture.Release();
                mat.Release();
            }
        }
    }
}
 

 

소스를 입력하고 빌드한다. (주석에 있는 내용을 사용하면 BitmapConverter.ToBitmap()을 사용하지 않아도 되므로 OpenCvSharp.Extensions도 설치할 필요가 없다)

 

 

실행하면 Start 버튼이 보인다.

 

Start 버튼을 클릭하면 Stop으로 바뀌고 카메라 영상이 재생된다.

 

※ 참고

아래 링크는 IP Camera를 이용한다. FFMpeg는 없어도 될거 같은데 사용한다. 나중에 IP Camera 생기면 확인해 보자.

OpenCvSharp Ip Camera

 

반응형

'OpenCV' 카테고리의 다른 글

Compiling and Running OpenPose from Source  (2) 2022.05.15
GDI+ and OpenCV - Bitmap to Mat & Mat to Bitmap Conversion  (0) 2022.01.02
OpenCvSharp for Network  (0) 2021.12.28
OpenCV with C#  (0) 2021.11.20
OpenCV with Qt and MSVC in Windows  (0) 2021.09.26
Posted by J-sean
:

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
: