T. Swiz
T. Swiz

Reputation: 57

Using OpenCV to crop image from background (strip extraction)

I'm trying to extract the pad section from the following image with OpenCv. Starting with an image like this: strip with background

I am trying to extract into an image like this:

enter image description here

to end up with an image something like this

enter image description here

I currently have the following

import cv2
import numpy as np
from matplotlib import pyplot as plt

img = cv2.imread('strip.png')

grayscale = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
_, thresholded = cv2.threshold(grayscale, 0, 255, cv2.THRESH_OTSU)
bbox = cv2.boundingRect(thresholded)
x, y, w, h = bbox
foreground = img[y:y+h, x:x+w]

cv2.imwrite("output.png", foreground)

Which outputs this:

enter image description here

Upvotes: 0

Views: 520

Answers (1)

MeiH
MeiH

Reputation: 1855

If you look closely to the upper and the lower parts of the image, it seems more cluttered and the center part (which is your desired output), it looks soft and smooth.

Since the center part is homogeneous , a smoothing filter (like an erosion) won't effect that part so much, the upper part otherwise, would change noticeably more.

At the first step, I remove the black background with a simple thresholding. At further I did some smoothing effect on the image and compute the difference between the result and the original image, then thresholded the final result to remove the unwanted pixels.

Then I did some morphology to remove noisy residual of the process. At the end with the help of boundingRect command, I extracted the desired segment (the white contour):

background removed:

enter image description here

the difference image after bluring with erosion:

enter image description here

the difference image after opening process and a threshold:

enter image description here

And finally the bounding box of the white objects:

enter image description here

The code I wrote (C++ opencv):

Mat im = imread("E:/t.jpg", 0);
resize(im, im, Size() , 0.3, 0.3); // # resizing just for better visualization

Mat im1,im2, im3;

// Removing the black background:
threshold(im, im1, 50, 255, THRESH_BINARY);
vector<vector<Point>> contours_1;
findContours(im1, contours_1, RETR_CCOMP, CHAIN_APPROX_NONE);

Rect r = boundingRect(contours_1[0]);

im(r).copyTo(im);
im.copyTo(im3);

imshow("background removed", im); 

// detecting the cluttered parts and cut them:
erode(im, im2, Mat::ones(3, 3, CV_8U), Point(-1, -1), 3);

im2.convertTo(im2, CV_32F);
im3.convertTo(im3, CV_32F);
subtract(im2, im3, im1);

double min, max;
minMaxIdx(im1, &min, &max);
im1 = 255*(im1 - min) / (max - min);
im1.convertTo(im1, CV_8U);

imshow("the difference image", im1);

threshold(im1, im1, 250, 255, THRESH_BINARY);

erode(im1, im1, Mat::ones(3, 3, CV_8U), Point(-1, -1), 3);
dilate(im1, im1, Mat::ones(3, 3, CV_8U), Point(-1, -1), 7);

imshow("the difference image thresholded", im1);

vector<Point> idx, hull;
vector<vector<Point>> hullis;
findNonZero(im1, idx);
Rect rr = boundingRect(idx);

rectangle(im, rr, Scalar(255, 255, 255), 2);

imshow("Final segmentation", im);

waitKey(0);

Upvotes: 2

Related Questions