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

The original program can be found inside OpenCV, it's called squares.cpp. The code below was modified to search squares only in the first color plane, but as it still detects many squares, at the end of the program I discard all of them except the first, and then call draw_squares()
to show what was detected. You can change this easilly to draw all of them and see everything that was detected.
You can do all sorts of thing from now own, including setting a (ROI) region of interest to extract the area that's inside the square (ignore everything else around it).
You can see that the detected rectangle is not perfectly aligned with the lines in the image. You should perform some pre-processing (erode?) operations in the image to decrease the thickness of lines and improve the detection. But from here on it's all 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;
}