ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • Day11
    교육/서울 ICT 이노베이션 고오급 시각과정 2021. 6. 30. 13:59
    728x90
    void qrcode_detector()
    {
        Mat src = imread("images/qrcode.jpg");
        Mat gray;
        cvtColor(src, gray, COLOR_BGR2GRAY);
        Mat bin;
        //이미지 이진화
        threshold(gray, bin, 128, 255, THRESH_BINARY);
        //Canny(gray, bin, 50, 200);	혹시나 너무 어둡거나 그늘진데서 썼을때 캐니를 쓰면 됨
        imshow("bin", bin);
        waitKey(0);
    
        //vector<vector<Point>> : 리스트의 리스트의 포인터
        //하나의 외곽선 : 포인터들의 집합->리스트의 포인터
        //외곽선은 여러개 존재->리스트의 리스트의 포인터
        vector<vector<Point>> contours;
        vector<Vec4i> hierarchy;	//칸투어들의 구조화된 정보 
        //외곽선 검출
        //외곽선은 닫힌 구조로 외곽선 안에 외곽선 안에 외곽선,,,->트리 구조로 나타낼 수 있음 : hierarchy
        //트리구조할지말지 : RETR_TREE
        //CHAIN_APPROX_NONE : 외곽선을 추출할 때 최적화할수있는 알고리즘
        findContours(bin, contours, hierarchy, RETR_TREE, CHAIN_APPORX_NONE, Point(0, 0));
    
        //모든 칸투어 그리기
        Mat dst = Mat::zeros(gray.size(), CV_8UC3);	//칸투어를 그릴 빈 캔버스
        for (int i = 0; i < contours.size(); i++)
        {
            //칸투어를 단순화시키는 함수
            vector<Point>app;
            //arcLength():외곽선길이출력
            //외곽선의 2%를 thresold로 준다->외곽선의 점을 찍는 걸 50개 밑으로
            //2~50개 안으로
            int thres = max((int)(arcLength(contours[i], true) * 0.02), 2);
            approxPolyDP(contours[i], app, thres, true);	//Ramer-Douglass-Peucker알고리즘
            contours[i] = app;
            Scalar c(rand() % 160, rand90 % 160, rand() % 160);	//랜덤한 rgb값(그릴 칸투어의 색깔)
            drawContours(dst, contours, i, c, 2);	//i번째 칸투어를 찾아서 그려줌
        }
        imshow("dst", dst);
        waitKey(0);
    
        //사각형만 그리기
        for (int i = 0; i < contours.size(); i++)
        {
            auto& con = contours[i];
            if (con.size() == 4)
            {
                drawContours(dst, contours, i, Scalar(255, 255, 255), 2);
            }
        }
        imshow("dst", dst);
        waitKey(0);
    
        //부모와 자신, 자녀 모두 사각형인 도형만 그리기
        for (int i = 0; i < contours.size(); i++)
        {
        	//auto&==vector<Point>&
            auto& con = contours[i];
            Vec4i& hie = hierarchy[i];
            int a = hie[3];
            //부모가 없거나 자식이 없으면 continue
            if (hie[3] == -1 || hie[2] == -1) continue;
            auto& parent = contours[hie[3]];
            auto& child = contours[hie[2]];
    		
            //qr코드 사각형의 비율내면
            if (parent.size() == 4 && child.size() == 4 && con.size() == 4) {
                /*double parentLen = arcLength(parent, true);
                double conLen = arcLength(con, true);
                double childLne = arcLength(child, true);
                printf("%lf %lf \n", parentLen/conLen, conLen/childLen);*/
                drawContours(dst, contours, i, Scalar(0, 255, 255), 2);
            }
        }
    }

    findContours()

    RANSAC알고리즘

    그림에서 outlier라고 표시된 부분과 같은 이상치를 제외하고 inlier만 이용해서 간격을 도출해내고 싶을 때 사용하는 알고리즘 중 하나

    랜덤으로 두 점을 골라서 모델을 만들고 inlier의 점의 개수를 뽑고 점들의 개수가 가장 많을 때가 최적의 해

    MeanShift?

    Meanshift알고리즘

    1. 랜덤으로 시작점을 정함

    2. 시작점을 기준으로 주위에 일정 threshold범위내에서 점의 중심을 찾음

    3. 새로 찾은 점의 중심을 기준으로 다시 2를 반복

    4. 점의 중심이 더 이상 움직이지 않을 때까지 실행

    왼쪽 그림에서 보면 1->2->3->4

     

    meanshift의 한계 : 주변에 inlier가 없으면 중심에 가기 전에 끝날 수 있음

    ->meanshift를 여러번 하자! = RANSAC

    MeanShift는 끝까지 가지만 RANSAC은 MeanShift를 1번(또는 2번)정도만

     

    객체검출

    1. 템플릿 매칭

    템플릿 : 찾고자 하는 대상이 되는 작은 크기의 영상

    템플릿 매칭 : 작은 크기의 템플릿 영상을 입력 영상 전체 영역에 대해 이동하면서 가장 비슷한 위치를 수치적으로 찾아내는 방식 ex)sliding window(detection하는 가장 기초적인 방법, 분류기를 이용해서 검출기를 만들 수 있음)

    element wise연산을 사용해서 검출함 ex) (∑(source-target)^2)/전체 크기 -> 픽셀마다 같은지 다른지 체크해서 원본과 샘플 영상이 같은지 확인

    원본영상이 회전하거나 크기가 다르거나 밝기나 색상이 다르거나 등 조금만 바뀌면 취약함 걍 다 취약 실무에선 잘 안씀

    그래서 영상을 이진화해서 템플릿 매칭함

    //이진화 - 밝기와 상관없이 템플릿 매칭을 하기 위해
    adaptiveThreshold(gray, bin, 255, ADAPTIVE_THRESH_MEAN_C, THRESH_BINARY_INV, 7, 10);
    //계산 편하게 하기 위해 밝은건 1 어두운건 0으로, 위에선 밝은거 255해놨는데 이러면 너무 큰값으로 됨
    adaptiveThreshold(gray, bin, 1, ADAPTIVE_THRESH_MEAN_C, THRESH_BINARY_INV, 7, 10);

    이진화해서 만든 원본영상
    템플릿

    TemplateMatchModes 열거형 상수

    • TM_SQDIFF : 제곱차 매칭 방법≒MSE 
      배경이랑 찾으려는 템플릿이랑 전부 매칭, 일반적으로 이걸 많이 사용
    • TM_CCORR : 상관관계 매칭 방법
      배경은 제외하고 템플릿에만 초점을 맞춰서 매칭, 템플릿만 매칭되면 된다할 때 사용
    matchTemplate(bin, temp, res, TM_SQDIFF);
    //임계값을 주어 원본영상에서 매칭된 부분확인
    threshold(res, found, 150, 255, THRESH_BINARY);

    TM_SQDIFF를 사용해서 템플릿 매칭을 했기 때문에

    매칭률이 높은 곳일수록 어둡게,

    매칭률이 낮은 곳일수록 밝게 나옴

    왼쪽의 이미지는 임계값(150)을 설정하여 

    임계값이하인 부분만 뽑아서 본 이미지

    검출된 부분이 점 하나로 나온 게 아니라

    여러 개의 점들로 이루어진 것을 알 수 있는데

    슬라이딩 윈도우를 하면서 템플릿을 옮겨가며 검출하는데

    윈도우내에 템플릿이 있으면 다 검출해서 여러개가 찍히는 것

    이 중에서 가장 적합한 것 하나만 찾아야하는데 이 기법을 NMS(Non-Maximum Suppression)이라고 함

     

    vector<Point> non_maximum(Mat src)
    {
    	vector<Point> result;	//최종적으로 가져와야할 point
    	int width = src.cols;
    	int height = src.rows;
    
    	int ws = src.step1();
    	float* dat = (float*)src.data;
    
    	vector<Vec3f> points;	//threshold이상인 point들을 모음
    
    	for (int y = 0; y < height; y++)
    	{
    		float* row = dat + y * ws;
    		for (int x = 0; x < width; x++)
    		{
    			if (row[x] < 150)
    			{
    				points.push_back(Vec3f(row[x], x, y));	//매칭강도(0에 가까울수록 매칭O, 클수록 매칭X), x좌표, y좌표
    			}
    		}
    	}
    
    	//매칭강도순으로 정렬
    	std::sort(points.begin(), points.end(), _sort_by_value);
    
    	//points에 있는 모든 점들에 대해
    	for (const Vec3f& v : points)
    	{
    		bool found = false;
            //다른 모든 점들이랑 비교
    		for (const Point& p : result)
    		{
    			//l1 norm, 점과 점이 겹치는지?
    			if (abs(v[1] - p.x) + abs(v[2] - p.y) < 20)
    			{
    				found = true;
    				break;
    			}
    		}
            //겹치면 continue
    		if (found)
    		{
    			continue;
    		}
    		//겹치지 않으면 result에 저장
    		result.push_back(Point(v[1], v[2]));
    	}
    	return result;	//그렇게 검출된 매칭된 사각형의 왼쪽 위 점들
    }

     

    	vector<Point> points = non_maximum(res);
    
    	Mat dst = img.clone();
    	for (const Point& p : points)
    	{
    		rectangle(dst, p, p + Point(temp.cols, temp.rows), Scalar(0, 255, 0), 2);
    	}
    	imshow("dst", dst);
    	waitKey(0);

     

    '교육 > 서울 ICT 이노베이션 고오급 시각과정' 카테고리의 다른 글

    Day13  (0) 2021.09.01
    Day12  (0) 2021.07.02
    Day10  (0) 2021.06.17
    Day9  (0) 2021.06.16
    Day8  (0) 2021.05.14

    댓글

Designed by Tistory.