OpenCV (Open Source Computer Vision Library)

  • 오픈 소스 컴퓨터 비전 라이브러리로, 실시간 이미지 처리와 컴퓨터 비전 애플리케이션 개발에 사용되는 프로그래밍 함수들의 모음
  • 주요기능
    • 이미지 처리
    • 특징 검출 및 기술자 추출
    • 객체 인식 및 추적
    • 카메라 캘리브레이션 및 3D 복원
    • 기계 학습
    • 옵티컬 플로우와 모션 분석

C# 에서의 활용 목적

  • 이미지 처리 과정을 손쉽게 하기 위해서

실습 (저장된 사진을 불러와 Gray로 바꾸고 PictureBox에 로드하기)

1. 프로젝트 생성

2. PictureBox, Button 컨트롤 가져다 두기

3. OpenCV 라이브러리 다운 (프로젝트 -> NuGet패키지 관리 -> 찾아보기 OpenCVSharp 검색)

(설치)

OpenCvSharp4,

OpenCvSharp4.Extensions (타입 변환등 OpenCvSharp4 라이브러리를 활용하는 작업을 쉽게 할 수 있도록 도와주는 각종 메서드가 사용가능해진다.)

4. 코드 작성

using OpenCvSharp;
using OpenCvSharp.Extensions;

namespace OpenCVTest2
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        private void button_Click(object sender, EventArgs e)
        {
            try
            {
                OpenFileDialog dig = new OpenFileDialog();
                if(dig.ShowDialog() == DialogResult.OK)
                {
                    // 해당 경로에서 이미지를 가지고와 Mat타입으로 변환
                    Mat image = Cv2.ImRead(dig.FileName);
                    Mat grayImage = new Mat();
                    Cv2.CvtColor(image, grayImage, ColorConversionCodes.BGR2GRAY);
					
                    // grayImage 위에 텍스트 쓰기
                    string text = "Hello, OpenCvSharp!";
                    OpenCvSharp.Point textPosition = new OpenCvSharp.Point(10, 50); // 이미지 상의 텍스트 위치
                    HersheyFonts font = HersheyFonts.HersheySimplex; // 폰트 선택
                    double fontSize = 1.0; // 폰트 크기
                    Scalar textColor = new Scalar(0, 255, 0); // 색상(Green)
                    int textThickness = 2; // 텍스트 두께
                    Cv2.PutText(grayImage, text, textPosition, font, fontSize, textColor, textThickness);

                    
                    // OpenCvSharp.Extensions의 메소드 ToBitMap()을 통해 Mat타입을 Bitmap 타입으로 변경
                    pictureBox.Image = grayImage.ToBitmap();
                }
            }catch(Exception ex)
            {
                MessageBox.Show(ex.Message);
            }
        }
    }
}

4-1. 이때 해당 오류가 발생하는데 아래 사이트에 접속 후 다음 과정을 진행해 주어야 오류를 해결 할 수 있다.

도움받은 블로그: https://luckygg.tistory.com/331 

https://github.com/shimat/opencvsharp

 

GitHub - shimat/opencvsharp: OpenCV wrapper for .NET

OpenCV wrapper for .NET. Contribute to shimat/opencvsharp development by creating an account on GitHub.

github.com

다운 받은 버전과 가급적 같은 버전을 선택하고 다운 후 압축풀기

여기서 NativeLib 폴더 > win 폴더 > x86 또는 x64의 OpenCvSharpExtern.dll 파일을 복사합니다.

그 후 해당 프로젝트 내에 파일을 복사 붙여넣고 

5. 결과 확인

MetroForm Ui: MIT 라이선스의 Winform의 UI를 예쁘게 바꿀 수 있는 UI 프레임워크  

해당 플러그인을 설치 후 Winform의 Form을 상속 받는 코드를 다음과 같이 수정하면 끝

원본 깃허브 링크: https://github.com/dennismagno/metroframework-modern-ui

 

GitHub - dennismagno/metroframework-modern-ui: My humble attempt to bring the new Modern UI alias Metro UI of Windows 8 to .NET

My humble attempt to bring the new Modern UI alias Metro UI of Windows 8 to .NET Windows Forms applications. - GitHub - dennismagno/metroframework-modern-ui: My humble attempt to bring the new Mode...

github.com

 

상황: 버튼을 누르면 같은 프로젝트 내의 다른 Form을 띄우고자 할 때

C#의 프로그램 파일 계층 구조

여기서 버튼을 누르면 같은 솔루션의 HomeWork3Update의 RoiForm을 화면에 나오게 하고자 한다.

참조 추가 그 후

namespace callTestForm
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        private void button1_Click(object sender, EventArgs e)
        {
            RoiForm roiForm = new RoiForm();
            roiForm.ShowDialog();
        }
    }
}

+ 만약 해당 폼을 열었을 때 다른 폼을 클릭 가능하게 하고 싶다면 ShowDialog() 대신 Show()로 하면 된다.

실행 모습

C# 윈도우 폼에서 특정 부분의 폰트를 설정하는 창을 만들어보자. 

Form만 Load 이벤트 핸들러를 달아주고 나머지 박스들은 더블 클릭을 통해 자동으로 만들어진 껍질 사용

 

운영체제에 설치된 폰트 목록을 가져와 콤보박스에 넣는 함수  

 // Form1의 load 이벤트 핸들러 
        private void addFont(object sender, EventArgs e)
        {
            // 운영체제에 설치되어 있는 폰트 목록 가져오기
            FontFamily[] fonts = FontFamily.Families;
            // foreach 문을 통해 conboBox에 하나씩 넣기
            foreach (FontFamily font in fonts)
                comboFontBox.Items.Add(font.Name);
        }

폰트 설정 변경에 공통으로 사용할 함수

 void changeFont()
        {
            FontStyle style = FontStyle.Regular; // FontStyle 일반 스타일 설정
            
            if(boldCheckBox.Checked)
                style |= FontStyle.Bold; // Bold 효과 추가
            if (italicCheckBox.Checked)
                style |= FontStyle.Italic; // Italic 효과 추가
            if (underlineCheckBox.Checked)
                style |= FontStyle.Underline; // Underline 효과 추가

            // 설정한 폰트로 바꾸기 Font("폰트 이름", int(사이즈), FontStyle); 
            textBox.Font = new Font((string)comboFontBox.SelectedItem, 12, style);
        }

 

전체코드:

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;

namespace FontBox
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        // Form1의 load 이벤트 핸들러 
        private void addFont(object sender, EventArgs e)
        {
            // 운영체제에 설치되어 있는 폰트 목록 가져오기
            FontFamily[] fonts = FontFamily.Families;
            // foreach 문을 통해 conboBox에 하나씩 넣기
            foreach (FontFamily font in fonts)
                comboFontBox.Items.Add(font.Name);
        }
        // 폰트 변화에 공통적으로 사용할 함수
        void changeFont()
        {
            FontStyle style = FontStyle.Regular; // FontStyle 일반 스타일 설정
            
            if(boldCheckBox.Checked)
                style |= FontStyle.Bold; // Bold 효과 추가
            if (italicCheckBox.Checked)
                style |= FontStyle.Italic; // Italic 효과 추가
            if (underlineCheckBox.Checked)
                style |= FontStyle.Underline; // Underline 효과 추가

            // 설정한 폰트로 바꾸기 Font("폰트 이름", int(사이즈), FontStyle); 
            textBox.Font = new Font((string)comboFontBox.SelectedItem, 12, style);
        }

        // Bold 체크 박스 클릭 이벤트 핸들러
        private void boldCheckBox_CheckedChanged(object sender, EventArgs e)
        {
            changeFont();
        }
        // Italic 체크 박스 클릭 이벤트 핸들러
        private void italicCheckBox_CheckedChanged(object sender, EventArgs e)
        {
            changeFont();
        }
        // 콤보박스 클릭 이벤트 핸들러
        private void comboFontBox_SelectedIndexChanged(object sender, EventArgs e)
        {
            changeFont();
        }
        // 밑줄 체크 박스 클릭 이벤트 핸들러
        private void underlineCheckBox_CheckedChanged(object sender, EventArgs e)
        {
            changeFont();
        }
    }
}

 

 

C#의 WinForm의 경우는 Java의 JFrame과는 다르게

폼 디자이너 툴을 제공하여 프로그래머가 일일이 컴포넌트를 구현할 필요 없이 그림 그리듯 GUI를 만드는 것이 가능하며

이를 WYSIWYG(What You See Is What You Get)방식의 개발이라고 합니다.

 

java: 간단한 로그인 화면 만들기

import javax.swing.*;
import java.awt.*;

public class SimpleLoginForm extends JFrame {
   public SimpleLoginForm(){
           JPanel p = new JPanel();
           Label lid = new Label("id");
           Label lpwd= new Label("pass");
           add(lid);
           add(lpwd);
           TextField tid = new TextField();
           TextField tpwd = new TextField();
           add(tid);
           add(tpwd);
           JButton jsave = new JButton("저장");
           add(jsave);
           lid.setBounds(80, 120, 40, 40);
           lpwd.setBounds(80,190,60,40);
           
           tid.setBounds(160, 120, 200, 40);
           tpwd.setBounds(160, 190, 200, 40);        
           jsave.setBounds(165, 480, 80, 30);
      add(p);
      setSize(600,600);
      setTitle("회원가입");
      setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
      setVisible(true);
   }    
   public static void main(String args[]) {
	   new SimpleLoginForm();
   }
}

JFrame을 상속 받고 일일이 컴포넌트들을 코딩하여 붙이고 위치 혹은 간격 설정을 프로그래머가 해주어야 한다.

정말 손이 많이 가고 번거롭다.

 

C#: 간단한 로그인 화면 만들기

이제 옆의 도구 상자에서 원하는 컴포넌트를 드래그 앤 드롭 하여 붙여넣고

적당히 클릭하여 내용을 바꿔주고 실행시키면

다음과 같이 자바와는 다르게 정말 간단하게 화면을 만들 수가 있다.

이것이 C#이다 교재를 바탕으로 윈도우 폼을 공부하던 중 초기에 콘솔 앱으로 프로젝트를 만들어 WinForm을 실행 하는 예제가 상속도 인식이 되지 않고 실행도 매끄럽게 되지 않아서 여러모로 조사하여 해결법을 찾게 공유하고자 한다. 

 

<Project Sdk="Microsoft.NET.Sdk">

	<PropertyGroup>
		<OutputType>Exe</OutputType>
		<TargetFramework>net6.0-windows</TargetFramework>
		<ImplicitUsings>enable</ImplicitUsings>

		<UseWindowsForms>true</UseWindowsForms>
		<ImportWindowsDesktopTargets>true</ImportWindowsDesktopTargets>

		<Nullable>enable</Nullable>
	</PropertyGroup>

</Project>

 

해당 내용을 다음과 같이 ]net.6.0 에 -windows 옵션 추가 및  useWindowsForms 옵션 true

ImportWindowsDesktopTargets 옵션 true를 주면

 

예시 코드:

using System;
using System.Windows.Forms;

namespace UsingApplication
{
    class MainApp : Form
    {
        static void Main(string[] args)
        {
            MainApp form = new MainApp();

            form.Click += new EventHandler((sender, eventArgs) =>
            {
                Console.WriteLine("Console Window...");
                Application.Exit();
            });

            Console.WriteLine("Starting Window Application ...");
            Application.Run(form);
            Console.WriteLine("Exiting Window Application ...");
        }
    }
}

 

다음과 같이 잘 작동되는 것을 알 수가 있다.

C#: C++에서 ++를 더 붙여 C++을 계승한다는 의미로 붙여진 객체지향 언어이자 .NET에 최적화된 언어

.NET(닷넷): 1900년대 말 마이크로소프트가 인터넷 서비스는 모든 종류의 기기에서 사용할 수 있어야 한다는 비전을 가지고 만들어진 플랫폼 사업적으로는 실패 하였으나 개발자들에게 .NET 클래스 라이브러리와 C#을 안겨주었다. 

CLR(Common Language Runtime): 모든 C#으로 만든 프로그램이 실행되는 곳

자바의 JVM 처럼 운영체제에서 일정 자원을 할당 받아서 C# 소스코드를 컴파일 및 실행 +가비지 컬렉터

목적: 자신이 설치한 플랫폼에 최적화시켜 컴파일한 후 실행시키기 위함 

 

실행과정(예시): 

1. 소스파일 컴파일시 아직 하드웨어가 이해할 수 없는 중간언어로 작성된 실행 파일 생성 

2. 사용자가 해당 파일을 실행시키면 CLR이 Just In Time(실시간) 컴파일 하여 하드웨어가 이해할 수 있는 네이티브 코드로 컴파일한 후 실행 

 

프로그램 파일 계층구조(예시): 

Hellow world 예제:

// 1번
using System; // 2번
using static System.Console; // 3번

namespace Hellow
{
    class MainApp
    {
        static void Main(String[] args)
        {
            System.Console.WriteLine("Hellow World"); // 1번
            Console.WriteLine("Hellow World"); // 2번
            WriteLine("Hellow World"); // 3번
        }
    }
}

using (~namespace): 뒤에 나올 namespace를 사용하겠다는 키워드 (비유: 자바에서의 import)

using static ~: 어떤 데이터 형식의 정적 멤버를 데이터 형식의 이름을 명시하지 않고 참조하겠다는 선언

대표적으로는 콘솔로부터 데이터를 출력 입력 받는 메소드들 Write(), Read()들이 존재

namespace: 하는 일(기능)이 비슷한 클래스, 구조체, 인터페이스, 대리자, 열거 형식 등을 하나의 이름 아래 묶어 둔 것

+만약 자바를 경험해본 사람이라면 namespace를 패키지 라고 생각하면 이해 하시는데 도움이 되실 겁니다.

static void Main(String[] args): 모든 프로그램이 실행되기 위해서는 반드시 하나 씩은 가지고 있어야 할 메소드(진입점)

 

   

 

+ Recent posts