user3079169
user3079169

Reputation: 53

Auto crop specific part of an image

First and foremost I'd like to stress I'm new to opencv.

I have this image of an electric meter such as this:

And I would like to process the image and just get this:

From what my lecturer has told us, we'll first need to find the contour and then process the image by just getting the rectangle part of the image.

Not sure if this is relevant, I'm using opencv 2.4.13

This is the code based on the tutorial for finding the contour

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

using namespace cv;
using namespace std;

Mat src; Mat src_gray;
int thresh = 100;
int max_thresh = 255;
RNG rng(12345);

/// Function header
void thresh_callback(int, void* );

/** @function main */
int main( int argc, char** argv )
{
  /// Load source image and convert it to gray
  src = imread( argv[1], 1 );

  /// Convert image to gray and blur it
  cvtColor( src, src_gray, CV_BGR2GRAY );
  blur( src_gray, src_gray, Size(3,3) );

  /// Create Window
  char* source_window = "Source";
  namedWindow( source_window, CV_WINDOW_AUTOSIZE );
  imshow( source_window, src );

  createTrackbar( " Canny thresh:", "Source", &thresh, max_thresh, thresh_callback );
  thresh_callback( 0, 0 );

  waitKey(0);
  return(0);
}

/** @function thresh_callback */
void thresh_callback(int, void* )
{
  Mat canny_output;
  vector<vector<Point> > contours;
  vector<Vec4i> hierarchy;

  /// Detect edges using canny
  Canny( src_gray, canny_output, thresh, thresh*2, 3 );
  /// Find contours
  findContours( canny_output, contours, hierarchy, CV_RETR_TREE, CV_CHAIN_APPROX_SIMPLE, Point(0, 0) );

  /// Draw contours
  Mat drawing = Mat::zeros( canny_output.size(), CV_8UC3 );
  for( int i = 0; i< contours.size(); i++ )
     {
       Scalar color = Scalar( rng.uniform(0, 255), rng.uniform(0,255), rng.uniform(0,255) );
       drawContours( drawing, contours, i, color, 2, 8, hierarchy, 0, Point() );
     }

  /// Show in a window
  namedWindow( "Contours", CV_WINDOW_AUTOSIZE );
  imshow( "Contours", drawing );
}

Upvotes: 0

Views: 1542

Answers (1)

Rick M.
Rick M.

Reputation: 3115

You should perform the following steps:

  1. Localize the LCD on the thermostat - This can be done using edge detection since there is enough contrast between the plastic shell and the LCD.

  2. Extract the LCD - Given an input edge map, you can find contours and look for outlines with a rectangular shape - the largest rectangular region should correspond to the LCD. A perspective transform will give you a nice extraction of the LCD.

Example : ( in python ) example.jpg

# load the example image
image = cv2.imread("example.jpg)

# pre-process the image by resizing it, converting it to gray scale,blurring it and computing an edge map
image = imutils.resize(image, height = 500)
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY) # OpenCV loads RGB as BGR
blurred = cv2.GaussianBlur(gray, (5, 5), 0) # Essentially reduces high frequency noise try with/without for your case
edged = cv2.Canny(blurred, 50, 200, 255);

Edge map

# Extracting LCD here
# find contours in the edge map, then sort them by their size in descending order
cnts = cv2.findContours(edged.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
cnts = cnts[0] if imutils.is_cv2() else cnts[1]
cnts = sorted(cnts, key=cv2.contourArea, reverse=True) # you can sort contours in C++ using implementation for std::vector
displayCnt = None

# loop over the contours
for c in cnts:
   # approximate the contour
   peri = cv2.arcLength(c, True)
   approx = cv2.approxPolyDP(c, 0.02 * peri, True)

   # if the contour has four vertices, then we have found the thermostat display
   if len(approx) == 4:
       displayCnt = approx.
       break

# extract the thermostat display, apply a perspective transform to it
warped = four_point_transform(gray, displayCnt.reshape(4, 2))
output = four_point_transform(image, displayCnt.reshape(4, 2))

Warped Image

The function four_point_transform is here.

You would probably need to do some adjustments to the code depending on your image and what you are getting. I will leave that to you.

Upvotes: 4

Related Questions