Reputation: 53
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
Reputation: 3115
You should perform the following steps:
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.
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.
# 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);
# 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))
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