OpenCV — найти форму объекта

Я изучаю OpenCV, и я достиг точки, где, что бы я ни делал, я застреваю.
Я пытаюсь изолировать объект (прямоугольный объект) от фона.

Примером является следующее изображение батареи:
батарейное фото

Я хочу замаскировать это изображение, чтобы единственное, что осталось, это объект.

Я пробовал следующее:

  • Thresholding
  • Определить края с помощью Canny
  • Найти контуры
  • Получить больше

Но я получаю какую-то странную область как большую. Вот результирующие картинки:

  • благоразумный
    хитрые края

  • Самый большой контур
    введите описание изображения здесь

Вот код, который я использую:

#include "opencv2/imgproc/imgproc.hpp"#include "opencv2/highgui/highgui.hpp"#include <stdlib.h>
#include <stdio.h>

using namespace cv;
using namespace std;int main( int, char** argv )
{
Mat src, srcGray,srcBlur,srcCanny;

string file = "samsung";
src = imread(file + ".jpg");
cvtColor(src, srcGray, CV_BGR2GRAY);
//bilateralFilter(srcGray, srcBlur,11, 17, 17);
srcBlur = srcGray.clone();
imshow("Filtered", srcBlur);
imwrite(file+"-filtered.jpg",srcBlur);

Canny(srcBlur, srcCanny, 0, 100, 3, true);
imshow("Canny", srcCanny);
imwrite(file+"-canny.jpg",srcCanny);vector< vector <Point> > contours; // Vector for storing contour
vector< Vec4i > hierarchy;
findContours( srcCanny.clone(), contours, hierarchy,CV_RETR_TREE, CV_CHAIN_APPROX_SIMPLE ); // Find the contours in the imageint largest_contour_index=0;
int largest_area=0;
for( int i = 0; i< contours.size(); i++ ){
double a=contourArea( contours[i],false);  //  Find the area of contour
if(a>largest_area){
largest_area=a;
largest_contour_index=i;                //Store the index of largest contour
}
}Mat dst(src.rows,src.cols,CV_8UC1,Scalar::all(0)); //create destination image
drawContours( dst,contours, largest_contour_index, Scalar(255,0,0),CV_FILLED, 8, hierarchy );
imshow("Largest", dst);
imwrite(file+"-largest.jpg",dst);

waitKey();
}

Этот кусок кода был предназначен для получения «маски» объекта, затем необходимо применить маскирование, но я не могу двигаться вперед, потому что не могу обнаружить объект

Моя цель — обнаружить прямоугольные объекты (только один объект на изображение) на разных изображениях.

Идея была взята из Вот, но мне не удается заставить этот код работать с менее контрастным изображением, как у меня.

Я тоже попробую этот который почти так же, как я хочу.

Я хочу выделить прямоугольный объект (который должен быть больше на изображении)

Заранее спасибо!

PS: хотя я могу перевести Python на C ++, я был бы признателен за ответ непосредственно в C ++, чтобы я мог проверить его быстрее.

0

Решение

Это то, что я взломал вместе, извините, это в Python 🙂

Во-первых, измените размер изображения до 1/4 от исходного размера (вероятно, он будет работать без изменения размера, хотя и с другими параметрами) и примените медианное размытие:

w, h, c = img_in.shape #img_in is the input image
resize_coeff = 0.25
img = cv2.resize(img_in, (int(resize_coeff*h), int(resize_coeff*w)))
img = cv2.medianBlur(img, 15)

Что хорошего в срединном размытии, так это в том, что он удаляет большую часть шума и мелких ненужных деталей, таких как эти синие линии маркера, сохраняя края более крупных фигур не размытыми. Теперь давайте применим обнаружение краев Canny:

img = cv2.Canny(img, 100, 200)

введите описание изображения здесь

К сожалению, на наших краях есть несколько крошечных зазоров, но это можно исправить с помощью расширения / разрушения:

kernel = np.ones((17, 17), np.uint8)
img = cv2.dilate(img, kernel, 1)
img = cv2.erode(img, kernel, 1)

введите описание изображения здесь

Теперь мы можем найти наши контуры, взять самый большой по площади, и это, вероятно, будет тем, что мы хотим:

img, contours, hierarchy = cv2.findContours(img, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
max_index, max_area = max(enumerate([cv2.contourArea(x) for x in contours]), key = lambda x: x[1])
max_contour = contours[max_index]

Рисуя его поверх исходного (масштабированного) изображения, мы получим это:

img_out = cv2.resize(img_in, (int(resize_coeff*h), int(resize_coeff*w)))
cv2.drawContours(img_out, [max_contour], 0, (0, 0, 255), 2)

введите описание изображения здесь

С помощью простого сглаживания контуров мы можем легко избавиться от проводов сверху, если захотим. Не знаю, что делать с тенью внизу.

5

Другие решения

Ваше входное изображение слишком велико, чтобы найти грубую последовательность контуров. Для изображений с более высоким разрешением вывод будет более детальным. В случае высокого разрешения, это не один контур, соответствующий наибольшему прямоугольнику. Так что решение
1. либо измените размер изображения, чтобы уменьшить, как я изменил размер изображения

resize(srcGray, srcGray, Size(), 0.25, 0.25);

и я получил этот вывод

введите описание изображения здесь

  1. Вы можете объединить близлежащие контуры в изображениях с высоким разрешением
    обратитесь к этому сообщению для слияния

(opencv) объединить контуры вместе

Но я бы предложил лучшее решение — изменить размер, а затем применить тот же код. Это легко и менее сложно.
ЗАМЕЧАНИЕ: выход здесь соответствует внутреннему прямоугольнику, вы можете дополнительно отрегулировать коэффициент изменения размера и пороговый коэффициент хитрости

2