프로그래밍

딥러닝 없이 사각형 인식 방법

satnurn 2026. 3. 20. 00:39
반응형

opencv만을 이용하여 사각형 이미지를 인식하기 위한 예제를 테스트 해보았으며, 이를 기록함.

 

 

 

 

 

# 환경

 - Ubuntu 22.04

 - opencv4.5.x

 

 

 

 

 

 

 

# 딥러닝 없이 사각형 인식 방법

1. 이미지의 전처리와 구조화

  • 전처리:
    노이즈를 제거(Blur)하고 밝기 변화가 심한 경계선(Canny Edge)만 남김
  • 구조화:
    흩어진 점들을 하나의 덩어리(Contour)로 묶고, 이를 다시 4개의 꼭짓점을 가진 다각형(ApproxPoly)으로 단순화함.

 

 

 

 

 

 

2. 정밀한 기하학적 연산

단순한 사각형 인식과 비스듬히 놓인 사각형의 각도를 파악함

  • 회전 사각형(RotatedRect):
    물체가 기울어져 있어도 이를 감싸는 최소 크기의 사각형을 찾아냄.
  • 좌표 및 각도 :
    사각형의 중심점(x, y), 가로·세로 길이(w, h), 그리고 지면 대비 회전 각도(Angle)를 계산함.

 

 

 

 

 

3. 필터링(노이즈 제거)

  • 면적 조건:
    너무 작은 먼지나 노이즈를 무시함 (ex.Area > 100).
  • 형태 조건:
    가로세로 비율(Aspect Ratio)을 계산하여 너무 길쭉한 사각형 등은 사각형에서 제외함.

 

 

 

 

 

 

4. 시각화

  • 동적 텍스트 배치:
    피타고라스 정리를 활용해 사각형의 회전 상태와 관계없이 텍스트가 물체 위쪽 적절한 위치에 표시되도록 연산 처리함.
  • 정보 표시:
    화면에 실시간으로 "(중심 좌표) + 회전 각도"를 출력하여 사각형의 기초 데이터로 활용할 수 있게 함.

 

 

 

 

 

# 예시 코드

이미지 데이터에서 직사각형 인식하여, 직사각형의 좌표, 각도 정보를 출력함.

#include <opencv2/opencv.hpp>
#include <iostream>
#include <vector>
#include <cmath>

using namespace cv;
using namespace std;

int main() {
    Mat src = imread("box.jpg");
    if (src.empty()) return -1;

    Mat gray, canned;
    cvtColor(src, gray, COLOR_BGR2GRAY);
    GaussianBlur(gray, gray, Size(3, 3), 0);
    Canny(gray, canned, 50, 150); // 에지 추출

    vector<vector<Point>> contours;
    findContours(canned, contours, RETR_EXTERNAL, CHAIN_APPROX_SIMPLE);

    for (const auto& contour : contours) {
        double perl = arcLength(contour, true);
        vector<Point> approx;
       
        // 외곽선 근사화 (정밀도 조절: 0.02 * 둘레)
        approxPolyDP(contour, approx, 0.02 * perl, true);

        // 사각형 조건 체크
        if (approx.size() == 4 && cv::isContourConvex(approx) && cv::contourArea(approx) > 100) {
   
            // 1. 회전된 사각형 정보 추출
            cv::RotatedRect rect = cv::minAreaRect(approx);
            float w = rect.size.width;
            float h = rect.size.height;

            // 2. 가로세로 비율 계산 (항상 긴 쪽을 짧은 쪽으로 나눔)
            float aspect_ratio = (w > h) ? (w / h) : (h / w);

            // 3. 조건 설정 (예: 가로 5px 이상, 세로 5px 이상, 비율은 5:1 이하)
            bool size_ok = (w > 5 && h > 5);
            bool ratio_ok = (aspect_ratio < 5.0); // 직사각형

            if (size_ok && ratio_ok) {
                // 각도 측정
                float angle = rect.angle;
                if (w < h) angle += 90.0f;

                // 직사각형 그리기
                cv::polylines(src, approx, true, cv::Scalar(0, 255, 0), 2);
               
                // 중심점 표시
                cv::circle(src, rect.center, 3, cv::Scalar(255, 0, 0), -1);
                std::string label = "(" + std::to_string((int)rect.center.x) + ", " + std::to_string((int)rect.center.y) +  ") " + std::to_string((double)angle) + "'";
                cv::putText(src, label, Point(rect.center.x - w/2, rect.center.y - sqrt(pow(w, 2)+pow(h, 2))/2 ),
                            cv::FONT_HERSHEY_SIMPLEX, 0.5, cv::Scalar(0, 255, 0), 1);
               
            }
        }
    }

    imshow("Square Detection", src);
    waitKey(0);
    return 0;
}

 

 *이는 테스트해본 코드이며 일부 수정해서 사용하면 됨.

 

 

 

 

 

 

반응형

'프로그래밍' 카테고리의 다른 글

유선 공유기(ipTime) 설정 방법  (0) 2026.05.09
apt update Warning/error 해결 방법  (0) 2025.12.24