The code to achieve the result below is a small modification of the one presented in this answer: how to determine the square :

The original program can be found inside OpenCV, it is called squares.cpp . The code below was modified to search for squares only in the first color plane, but since it still detects many squares, at the end of the program I drop all of them except the first, and then call draw_squares()
to show what was detected. You can change this easilly to draw them all and see everything that has been discovered.
Now you can do all kinds of things, including setting the region of interest (ROI) to extract the region that is inside the square (ignore everything else around it).
You can see that the detected rectangle is not quite aligned with the lines in the image. You must perform some preprocessing operations (erode?) On the image to reduce line thickness and improve detection. But from here everything is on you:
#include <cv.h> #include <highgui.h> using namespace cv; double angle( cv::Point pt1, cv::Point pt2, cv::Point pt0 ) { double dx1 = pt1.x - pt0.x; double dy1 = pt1.y - pt0.y; double dx2 = pt2.x - pt0.x; double dy2 = pt2.y - pt0.y; return (dx1*dx2 + dy1*dy2)/sqrt((dx1*dx1 + dy1*dy1)*(dx2*dx2 + dy2*dy2) + 1e-10); } void find_squares(Mat& image, vector<vector<Point> >& squares) { // TODO: pre-processing // blur will enhance edge detection Mat blurred(image); medianBlur(image, blurred, 9); Mat gray0(blurred.size(), CV_8U), gray; vector<vector<Point> > contours; // find squares in the first color plane. for (int c = 0; c < 1; c++) { int ch[] = {c, 0}; mixChannels(&blurred, 1, &gray0, 1, ch, 1); // try several threshold levels const int threshold_level = 2; for (int l = 0; l < threshold_level; l++) { // Use Canny instead of zero threshold level! // Canny helps to catch squares with gradient shading if (l == 0) { Canny(gray0, gray, 10, 20, 3); // // Dilate helps to remove potential holes between edge segments dilate(gray, gray, Mat(), Point(-1,-1)); } else { gray = gray0 >= (l+1) * 255 / threshold_level; } // Find contours and store them in a list findContours(gray, contours, CV_RETR_LIST, CV_CHAIN_APPROX_SIMPLE); // Test contours vector<Point> approx; for (size_t i = 0; i < contours.size(); i++) { // approximate contour with accuracy proportional // to the contour perimeter approxPolyDP(Mat(contours[i]), approx, arcLength(Mat(contours[i]), true)*0.02, true); // Note: absolute value of an area is used because // area may be positive or negative - in accordance with the // contour orientation if (approx.size() == 4 && fabs(contourArea(Mat(approx))) > 1000 && isContourConvex(Mat(approx))) { double maxCosine = 0; for (int j = 2; j < 5; j++) { double cosine = fabs(angle(approx[j%4], approx[j-2], approx[j-1])); maxCosine = MAX(maxCosine, cosine); } if (maxCosine < 0.3) squares.push_back(approx); } } } } } void draw_squares(Mat& img, vector<vector<Point> > squares) { for (int i = 0; i < squares.size(); i++) { for (int j = 0; j < squares[i].size(); j++) { cv::line(img, squares[i][j], squares[i][(j+1) % 4], cv::Scalar(0, 255, 0), 1, CV_AA); } } } int main(int argc, char* argv[]) { Mat img = imread(argv[1]); vector<vector<Point> > squares; find_squares(img, squares); std::cout << "* " << squares.size() << " squares were found." << std::endl; // Ignore all the detected squares and draw just the first found vector<vector<Point> > tmp; if (squares.size() > 0) { tmp.push_back(squares[0]); draw_squares(img, tmp); } //imshow("squares", img); //cvWaitKey(0); imwrite("out.png", img); return 0; }