상세 설명 은 OpenCV 를 이용 하여 그림 의 사각형 영역 추출(PPT 화면 등)
최근 에 큰 프로젝트 에 참 가 했 는데 제목 은 컴퓨터 시각 과 관련 되 고 선배 가 이미 지 를 수정 하 는 블 로그 링크 를 보 내 서 이 문제 로 OpenCV 에 입문 할 계획 이다.
문 제 를 분석 하 다
사진 속 의 PPT 구역 은 항상 x,y,z 세 축 을 따라 경사 가 있다(아래 그림).사진 을 평행 위치 로 뒤 집 으 려 면 투시 변환 이 필요 하고 투시 변환 은 같은 픽 셀 점 에서 전후의 좌 표를 바 꿔 야 한다.이 를 통 해 알 수 있 듯 이 사각형 구역 의 네 각 의 좌 표를 추출 하여 변환 전의 좌표 로 하고 변 경 된 좌 표 는 사진 의 네 구석 으로 설정 할 수 있 으 며 투영 변 화 를 통 해 사각형 구역 은 뒤 집 히 고 이미지 가 가득 할 것 이다.
그래서 우리 가 해결 해 야 할 문 제 는 사각형 의 네 구석 을 추출 하고 투시 변환 을 하 는 것 으로 바 뀌 었 다.
직사각형 구석 좌표 추출
사각형 의 검 측 은 주로 추출 가장자리 이 고 PPT 디 스 플레이 부분의 밝 기 는 보통 주변 환경 보다 높 습 니 다.우 리 는 그림 의 한도 값 화 를 통 해 PPT 부분 과 주변 환경 을 뚜렷하게 구분 할 수 있 습 니 다.이것 은 뒤의 가장자리 검 측 에 매우 도움 이 됩 니 다.
직사각형 을 검 측 하고 좌 표를 추출 하려 면 이미지 에 대해 예비 처리,가장자리 검 측,윤곽 추출,돌출 가방 검 측,각 점 검 측 을 해 야 한다.
예비 처리
휴대 전화 로 찍 은 사진 의 픽 셀 이 높 을 수 있 기 때문에 처리 속 도 를 높이 기 위해 우 리 는 먼저 사진 을 줄 였 고 여 기 는 4 배 줄 었 다.
pyrDown(srcPic, shrinkedPic); //
pyrDown(shrinkedPic, shrinkedPic);
그 레이스 케 일 로 전환
cvtColor(shrinkedPic, greyPic, COLOR_BGR2GRAY); //
중간 값 필터
medianBlur(greyPic, greyPic, 7); //
2 값 그림 으로 전환
threshold(greyPic, binPic, 80, 255, THRESH_BINARY); //
이때 그림 은 이미 이렇게 변 했다.PPT 부분 이 환경 과 분 리 된 것 을 알 수 있다.
테두리 검출 및 윤곽 처리
Canny 테두리 검출 진행
Canny(binPic, cannyPic, cannyThr, cannyThr*FACTOR); //Canny
여기cannyThr = 200, FACTOR = 2.5
가장자리 특징 이 너무 뚜렷 하기 때문에 계 수 는 100-600 범위(구체 적 인 숫자 는 차이 가 있 을 수 있 고 어차피 범위 가 매우 크다)에서 발생 하 는 효 과 는 거의 같다.윤곽 추출
vector<vector<Point>> contours; //
vector<Vec4i> hierarchy;
findContours(cannyPic, contours, hierarchy, RETR_CCOMP, CHAIN_APPROX_SIMPLE); //
findContour
함수 원형 은 다음 과 같다.
CV_EXPORTS_W void findContours( InputOutputArray image, OutputArrayOfArrays contours,
OutputArray hierarchy, int mode,
int method, Point offset = Point());
검 측 된 윤곽 이 모두 존재 합 니 다contours
.각 윤곽 은 하나 로 저 장 됩 니 다vector<Point>
.hierarchy
그림 의 토폴로지 정 보 를 포함 하여 선택 할 수 있 는 출력 벡터 입 니 다.여 기 는 사용 하지 않 는 것 을 선택 할 수 있 습 니 다.우 리 는 반복 적 으로 호출
drawContours
함수 로 윤곽 을 그 릴 수 있다.
linePic = Mat::zeros(cannyPic.rows, cannyPic.cols, CV_8UC3);
for (int index = 0; index < contours.size(); index++){
drawContours(linePic, contours, index, Scalar(rand() & 255, rand() & 255, rand() & 255), 1, 8/*, hierarchy*/);
}
drawContours
함수 원형:
CV_EXPORTS_W void drawContours( InputOutputArray image, InputArrayOfArrays contours,
int contourIdx, const Scalar& color,
int thickness = 1, int lineType = LINE_8,
InputArray hierarchy = noArray(),
int maxLevel = INT_MAX, Point offset = Point() );
작용 은contours
중의 제contourIdx
조 윤곽 을color
색 으로image
중thickness
선의 굵기,contourIdx
음수 일 때 모든 윤곽 을 그 리 는 것 이다여기 서 주의해 야 할 것 은 윤곽 을 그리 기 전에 출력 행렬 에 공간 을 미리 배정 해 야 합 니 다.그렇지 않 으 면 다음 과 같은 오류 가 발생 할 수 있 습 니 다.
OpenCV(3.4.1) Error: Assertion failed (size.width>0 && size.height>0) in cv::imshow, file C:\build\master_winpack-build-win64-vc15\opencv\modules\highgui\src\window.cpp, line 356
면적 이 가장 큰 윤곽 을 추출 하고 다각형 으로 윤곽 을 포위 합 니 다.
위의 윤곽 도 에서 보 듯 이 PPT 의 사각형 은 이미 그림 의 주요 부분 이 되 었 고 그 다음 의 사 고 는 면적 이 가장 큰 윤곽 을 추출 하여 사각형 의 윤곽 을 얻 는 것 이다.
vector<vector<Point>> polyContours(contours.size());
int maxArea = 0;
for (int index = 0; index < contours.size(); index++){
if (contourArea(contours[index]) > contourArea(contours[maxArea]))
maxArea = index;
approxPolyDP(contours[index], polyContours[index], 10, true);
}
contourArea
윤곽 의 면적 을 계산 하 는 데 쓰 인 다.approxPolyDP
다각형 으로 윤곽 을 둘러싸 고 엄격 한 사각형 을 얻 을 수 있어 각 점 을 찾 는 데 도움 이 된다.직사각형 을 그 려 도 마찬가지 로 미리
Mat
공간 을 분배 해 야 한다.
Mat polyPic = Mat::zeros(shrinkedPic.size(), CV_8UC3);
drawContours(polyPic, polyContours, maxArea, Scalar(0,0,255/*rand() & 255, rand() & 255, rand() & 255*/), 2);
그림 과 같이 다음 에 우 리 는 네 개의 각 의 좌 표를 추출 하기 만 하면 된다.
볼록 가방 찾기
vector<int> hull;
convexHull(polyContours[maxArea], hull, false); //
convexHull
함수 원형
CV_EXPORTS_W void convexHull( InputArray points, OutputArray hull,
bool clockwise = false, bool returnPoints = true );
hull
는 출력 매개 변수 이 고clockwise
볼록 가방 은 시계 반대 방향 으로 결정 한다.returnPoints
진짜 일 때 볼록 가방 의 각 점 을 되 돌려 주 고 그렇지 않 으 면 각 점 의 지 수 를 되 돌려 준다.hull
유형vector<int>
으로 할 수 있 습 니 다.이때 돌출 점 이 원 그림 에 있 는 아래 표 시 된 색인 을 되 돌려 줍 니 다.우 리 는 점 과 다각형 을 원 그림 에 추가 하여 효 과 를 볼 수 있다.
for (int i = 0; i < hull.size(); ++i){
circle(polyPic, polyContours[maxArea][i], 10, Scalar(rand() & 255, rand() & 255, rand() & 255), 3);
}
addWeighted(polyPic, 0.5, shrinkedPic, 0.5, 0, shrinkedPic);
지금 우 리 는 이미 비교적 정확하게 필요 한 점 을 얻 었 으 니,다음은 이 점 을 이용 하여 좌 표를 매 핑 해 야 한다.
투영 변환
투영 변환 은 픽 셀 이 두 좌표계 의 좌표 에 일일이 대응 해 야 한다.비록 우 리 는 이미 네 개의 좌 표를 가지 고 있 지만 그들의 위 치 를 구분 하지 못 했다.
새 두 배열
Point2f srcPoints[4], dstPoints[4];
dstPoints[0] = Point2f(0, 0);
dstPoints[1] = Point2f(srcPic.cols, 0);
dstPoints[2] = Point2f(srcPic.cols, srcPic.rows);
dstPoints[3] = Point2f(0, srcPic.rows);
dstPoints
저 장 된 것 은 변 경 된 각 점 의 좌표 이 고 왼쪽 위,오른쪽 위,오른쪽 아래,왼쪽 아래 이다.srcPoints
위 에서 얻 은 네 개의 각 의 좌 표를 저장 합 니 다.다음은 얻 은 네 가지 점 을 처리 하 겠 습 니 다.
for (int i = 0; i < 4; i++){
polyContours[maxArea][i] = Point2f(polyContours[maxArea][i].x * 4, polyContours[maxArea][i].y * 4); //
}
//
bool sorted = false;
int n = 4;
while (!sorted){
for (int i = 1; i < n; i++){
sorted = true;
if (polyContours[maxArea][i-1].x > polyContours[maxArea][i].x){
swap(polyContours[maxArea][i-1], polyContours[maxArea][i]);
sorted = false;
}
}
n--;
}
if (polyContours[maxArea][0].y < polyContours[maxArea][1].y){
srcPoints[0] = polyContours[maxArea][0];
srcPoints[3] = polyContours[maxArea][1];
}
else{
srcPoints[0] = polyContours[maxArea][1];
srcPoints[3] = polyContours[maxArea][0];
}
if (polyContours[maxArea][9].y < polyContours[maxArea][10].y){
srcPoints[1] = polyContours[maxArea][2];
srcPoints[2] = polyContours[maxArea][3];
}
else{
srcPoints[1] = polyContours[maxArea][3];
srcPoints[2] = polyContours[maxArea][2];
}
즉,먼저 네 개의 점 의 x 좌 표를 거품 정렬 하여 좌우 로 나 눈 다음 에 두 쌍 의 좌표 의 y 값 에 따라 상하 로 나 누 는 것 이다.(필 자 는 볼록 가방 의 시계 반대 방향 순서 와 볼록 가방 점 과 원점 의 거 리 를 통 해 위치 정 보 를 살 려 고 했 지만 모두 실패 로 끝났다)
좌표 변환 은 행렬 연산 이 필요 합 니 다.OpenCV 에서 우리 에 게
getPerspectiveTransform
함 수 를 제공 하여 행렬 을 얻 을 수 있 습 니 다.
Mat transMat = getPerspectiveTransform(srcPoints, dstPoints); //
그 다음 에 좌표 변환 을 할 때 인터넷 에서 찾 아 낸 절 차 는 모두perspectiveTransform
함수 로 바 뀌 었 지만 여러 번 오류 가 발생 했 습 니 다.구 글 은 오 랜 시간 이 지나 서 야 원래 이 함수 의 입력 과 출력 매개 변수 가 모두 점 집합 이라는 것 을 알 게 되 었 습 니 다.우리 의 이 장면 은 사용 하기에 비교적 귀 찮 습 니 다.한편,
warpPerspective
함 수 는 입력Mat
유형의 데 이 터 를 직접 입력 할 수 있어 서 비교적 편리 하 다.
warpPerspective(srcPic, outPic, transMat, srcPic.size()); //
매개 변 수 는 입 출력 이미지,변환 매트릭스,크기 입 니 다.좌표 가 바 뀌 면 우리 가 원 하 는 최종 그림 을 얻 을 수 있다.
총결산
우 리 는 스크린 밝기 가 비교적 높 은 특징 을 이용 하여 이치 화 를 통 해 윤곽 을 돋 보이 게 하고 좌 표를 추출 하여 투시 변환 을 한다.
그러나 직사각형의 밝기 가 배경 과 크게 다 르 지 않 으 면 이런 방법 으로 윤곽 을 감지 하기 어렵 다 는 한계 가 있다.
이상 이 바로 본 고의 모든 내용 입 니 다.여러분 의 학습 에 도움 이 되 고 저 희 를 많이 응원 해 주 셨 으 면 좋 겠 습 니 다.
이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 AI 엔진은 머신러닝 분석(스마트 모델이 방금 만들어져 부정확한 경우가 있을 수 있음)을 통해 가장 유사한 기사를 추천합니다:
Visual Studio 2017에서 OpenCV 템플릿 프로젝트 만들기・Windows 7 Professional 64bit ・Visual Studio 2017 Version 15.9.14 · OpenCV 3.4.1 OpenCV의 도입 방법 등은 아래를 참조하십시오. Visual Stu...
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
CC BY-SA 2.5, CC BY-SA 3.0 및 CC BY-SA 4.0에 따라 라이센스가 부여됩니다.