Wrapping text in pads using ncurses. (In C) - c

I've been playing around with ncurses and I've found very little useful information on the net dealing with pads. I understand that pads are a sort of larger window off screen, sections of which can be printed on smaller windows on screen.
I wrote a program to print the context of a pad on screen. The problem is that the program only seems to print "line-to-line" and doesn't wrap around text.
The program's output is something like this:
abcdefghij
abcdefghij
abcdefghij
But it should be like this:
abcdefghij
klmnopqrst
uvwxyzabc
In the later case the same line "wraps" around rather than multiple lines being printed.
Can any ncurses gurus tell me how to achieve this wrapping functionality? (I.e: Magic?)
Ask if you need further details, source code of the program:
#include <unistd.h>
#include <curses.h>
int main()
{
WINDOW *pad_ptr;
int x, y;
int pad_lines;
int pad_cols;
char disp_char;
initscr();
pad_lines = LINES + 50;
pad_cols = COLS + 50;
pad_ptr = newpad(pad_lines, pad_cols);
disp_char = 'a';
for(x = 0; x < pad_lines; x++)
{
for(y = 0; y < pad_cols; y++)
{
mvwaddch(pad_ptr, x, y, disp_char);
if(disp_char == 'z')
disp_char = 'a';
else
disp_char++;
}
}
/* We just filled the pad with letters from the alphabet. */
/* Now we will fill part of the main window with a 10x10 section
* of the pad.
* Notice that the text does not wrap around. (Where is 'k'?)
*/
prefresh(pad_ptr, 0, 0, 3, 3, 9+3, 9+3);
sleep(3000);
// prefresh(pad_ptr, LINES + 5, COLS + 7, 5, 5, 21, 19);
// sleep(4);
delwin(pad_ptr);
endwin();
exit(0);
}

You are misunderstanding the way pads work.
Pads allow you to create a window (possibly larger than the physical screen) and then show a subset of the window. When you display the pad with prefresh you are displaying a view of a subset of the pad. The content is not altered (or wrapped) when you display the subset of the pad.
If you Add the code below to your sample you will see the viewport moving each time you press a key but the content of the pad is not changed.
for (x=0; x<10; x++) {
prefresh(pad_ptr, 0, x, 3, 3, 9+3, 9+3);
wgetch(pad_ptr);
}

Change pad_lines and pad_cols to 9 and see if you are happier.
Let's say LINES and COLS are 100 on your system. You are creating a 10+k array in the pad something like:
a-z..a-z..a-z..a-k
l-z..a-z..a-z..a-d
e-z..a-z..a-z..a-o //etc
and then your prefresh() displays the first 9 columns (of 9 lines) on the screen.

Related

ncurses displays characters horizontally instead of vertically

I am writing a simple game in console using ncurses on linux and I have a very odd problem and I cannot find out what's wrong in my code the problem is that when I run my program my screen should look like this
which it does but after my draw() function runs more than 10 times i get something like this
here is my code:
#include <stdio.h>
#include <ncurses.h>
#include <stdlib.h>
#define END endwin();return 0
#define LN 5
#define RN 100
int display [LN][RN] = {
// 1 2 3 4 5 6 7 8 9 q w e r t y u
{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},//1
{0,0,'#',0,0,0,0,0,0,0,0,0,0,0,0},//2
{0,0,'#',0,0,0,0,0,0,0,0,0,0,0,0},//3
{0,0,'#',0,0,0,0,0,0,0,0,0,0,0,0},//4
{1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1} //5
};
void setup(){//cr
initscr();
cbreak();
nodelay(stdscr,TRUE);
keypad(stdscr, TRUE);
noecho();
curs_set(0);
for(int i = 0 ; i < RN ; i++){
display[LN - 1][i] = 1;
}
return;
}
void draw(){
system("clear");
for(int i = 0; i < LN ; i++){
for(int j = 0; j < RN ; j++){
if(display[i][j] == 1){
addch(ACS_HLINE);
}
else if(display[i][j] == 0){
addch(' ');
}
else printw("%c",display[i][j]);
}
addch('\n');
}
refresh();
system("sleep 0.3");
return;
}
and I'm using arch
[n]curses keeps an internal map of what the screen is supposed to look like. It uses that map to do efficient updates when you call refresh(). This only works if the library is exclusively in control of the output to the terminal.
When you do terminal output through some other method, like system("clear"), the library no longer has an accurate map of the state of the terminal. The next update sends the escape sequences and printable strings necessary to go from state A to state B, but the terminal is actually in state C, and you end up with something crazy.
There is a curses erase() function which clears the screen, which you should use instead. It's equivalent to using a bunch of addch calls to write blanks in every position.
There's also a clear() function, which does an erase() and a clearok(TRUE), which tells the library to throw away its internal map and redraw the whole screen. This can be used to recover from the situation when something bad has happened, corrupting the screen. So, ironically, you could have gotten away with system("clear") if you'd done a clear() afterward.

Strange output when using system("clear") command in C program

I have the following code
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <time.h>
#include <stdbool.h>
#define dimensions 5
int RandomNumInRange(int M, int N)
{
return M + rand() / (RAND_MAX / (N - M + 1) + 1);
}
char ** CreateWorld(int dim)
{
int i,j;
char **world = malloc(dim *sizeof(char*));
for(i=0;i<dim;i++)
world[i]=malloc(dim*sizeof(char));
for(i=0;i<dim;i++)
for(j=0;j<dim;j++)
world[i][j]=42;
return world;
}
void CreateCastle(char **world)
{
//assuming world is big enough
//to hold a match of 2
int randRow,randCol;
//1 to dimension -2 so we can spawn a 3x3 castle
randRow = RandomNumInRange(1,dimensions-2);
randCol = RandomNumInRange(1,dimensions-2);
printf("position: %d %d\n", randRow, randCol);
world[randRow][randCol]='c';
//fill the rest so castle is 3x3
//assuming there is enough space for that
world[randRow-1][randCol-1]=35;
world[randRow-1][randCol]=35;
world[randRow-1][randCol+1]=35;
world[randRow][randCol-1]=35;
world[randRow][randCol+1]=35;
world[randRow+1][randCol-1]=35;
world[randRow+1][randCol]=35;
world[randRow+1][randCol+1]=35;
}
void DisplayWorld(char** world)
{
int i,j;
for(i=0;i<dimensions;i++)
{
for(j=0;j<dimensions;j++)
{
printf("%c",world[i][j]);
}
printf("\n");
}
}
int main(void){
system("clear");
int i,j;
srand (time(NULL));
char **world = CreateWorld(dimensions);
DisplayWorld(world);
CreateCastle(world);
printf("Castle Positions:\n");
DisplayWorld(world);
//free allocated memory
free(world);
//3 star strats
char ***world1 = malloc(3 *sizeof(char**));
for(i=0;i<3;i++)
world1[i]=malloc(3*sizeof(char*));
for(i=0;i<3;i++)
for(j=0;j<3;j++)
world1[i][j]="\u254B";
for(i=0;i<3;i++){
for(j=0;j<3;j++)
printf("%s",world1[i][j]);
puts("");
}
free(world1);
//end
return 0 ;
}
If I use the system("clear") command, I get a line consisting of "[3;J"
followed by an expected output. If I run the program again, I get the same gibberish, then many blank newlines, then the expected output. If I put the system("clear") command in comments then both the "[3;J" and the blank newlines don't show and the output is expected.
Edit: it seems the error is not in the code, but rather in the way the terminal on my system is (not) set. Thank you all for your input, I definitely have a lot of interesting stuff to read and learn now.
The codes being sent by your clear command from don't seem to be compatible with the Gnome terminal emulator, which I believe is what you would be using.
The normal control codes to clear a console are CSI H CSI J. (CSI is the Control Sequence Initializer: an escape character \033 followed by a [). CSI H sends the cursor to the home position, and CSI J clears from the cursor position to the end of the screen. You could also use CSI 2 J which clears the entire screen.
On Linux consoles and some terminal emulators, you can use CSI 3 J to clear both the entire screen and the scrollback. I would consider it unfriendly to do this (and the clear command installed on my system doesn't.)
CSI sequences can typically contain semicolons to separate numeric arguments. However, the J command doesn't accept more than one numeric argument and the semicolon seems to cause Gnome terminal to fail to recognize the control sequence. In any event, I don't believe Gnome terminal supports CSI 3 J.
The clear command normally uses the terminfo database to find the correct control sequences for the terminal. It identifies the terminal by using the value of the TERM environment variable, which suggests that you have to wrong value for that variable. Try setting export TERM=xterm and see if you get different results. If that works, you'll have to figure out where Linux Mint configures environment variables and fix it.
On the whole, you shouldn't need to use system("clear") to clear your screen; it's entirely too much overhead for such a simple task. You would be better off using tputs from the ncurses package. However, that also uses the terminfo database, so you will have to fix your TERM setting in any case.

RNG Character Printing Function - More than one line of RNG characters per page? : C

So, I wrote a function (and an RNG function, which the aforementioned function calls) to print a random number of asterisks to the console window, until it hits 90 spaces. The asterisks represent the movement of a car, and the 90 spaces is the length of the track. The code I've included below prints a random number of asterisks until it hits 90 spaces, assuming the fnvMoveSpaces() function is called in main and the user presses a key to resume the loop after each system("PAUSE") until 90 spaces is hit.
My question is, looking at the provided code, how would I get four separate lines of totally independent RNG character printing on the same page of the console window? It needs to look like a legitimate race, on the same screen.
What I've tried:
1) Separate functions for each line, called in main:
Won't work, as they don't happen at the same time. Results in four different pages. I.e. the user has to press a key to get through system("PAUSE") until it hits 90 spaces, then the next function does the same, then the next, and the next. Also, if the loop/function call is outside of the fnvMoveSpaces() main loop, they don't print to the same page.
2) Putting four of the same for loops in the fnvMoveSpaces() function:
This prints four lines to the same screen, but they all move the same increment, because they are pulling from the same RNG value.
Basically, the RNG values for each line need to be totally independent of one another. Would having a different seed value for each line be the answer? I have no idea...
/* - - DEFINED - - */
// Constants of RNG for spaces moved
#define TRACK_LENGTH 90
#define MAX_MOVE_SPACES 10
#define MIN_MOVE_SPACES 1
// Assume fnvMoveSpaces call in main
// Function to create random number for car movement
int fniRandGenMove()
{
// Declare
int randInt;
// Initialize random seed
srand(time(NULL));
// Formula for RNG (1-10) based on global-defined numbers
randInt = (rand() % (MAX_MOVE_SPACES - MIN_MOVE_SPACES + 1) + MIN_MOVE_SPACES);
return (randInt);
}
void fnvMoveSpaces()
{
// Declare
int i;
int iMoveSum;
// Outer for loop to maintain the sum of asterisks
for(iMoveSum = 0; iMoveSum <= TRACK_LENGTH; iMoveSum += fniRandGenMove())
{
// Inner for loop to print asterisks
for(i = 0; i < iMoveSum; i++)
{
putchar('*');
}
// Newline for next line of asterisks
printf("\n");
/*
I'm assuming three more for loops... I tried a bunch of
combinations of things, even making new iMoveSums
(2, 3 and 4) and doing for loops.
But, no luck.
I should also not that making four separate functions for each
line of asterisks will not work, unless there is a way to call all
four at once in main. Separate functions results in separate screens
in the console window. In addition, if the four 'putchar' blocks
are not in the same loop as a whole, the first one will print, hit
90 spaces, then the second, etc... They aren't on the same screen.
*/
// System pause to wait for user
system("PAUSE");
// Clear screen
system("CLS");
}
}
Just to clarify, the current output of this in the console window is this:
**.....*
(Writing in a form of enumeration; no periods actually output.)
Until 90 spaces are hit, then the program closes. Also keep in mind that it prints in random increments each time the user presses a key after system("PAUSE"), until 90. So, not all the asterisks print at once.
What I want it to output is something like this:
*...**
*.........**
**........................*
**..............*
With each line randomly generating its own independent movement increment, until 90 spaces are hit.
Hope that helps.
Thanks,
Bagger
Okay, I got it worked out. Keep in mind that at some point in the near future, I intend to replace the structures with some file I/O. Also, fniRandGenMove is the same as in the question, just move the seed to main, so it only seeds once.
But it works perfectly... the 'cars' race across the console window! It's actually really neat.
void fnvMoveSpaces(int iAutoManual)
{
// Declare
int i, j;
// Declare structures
struct Car stCars[4];
stCars[0].iPosition = 0;
stCars[1].iPosition = 0;
stCars[2].iPosition = 0;
stCars[3].iPosition = 0;
stCars[0].iCarNumber = 1;
stCars[1].iCarNumber = 2;
stCars[2].iCarNumber = 3;
stCars[3].iCarNumber = 4;
struct Car furthestCar;
furthestCar.iPosition = 0;
furthestCar.iCarNumber = 0;
do
{
for(i = 0; i < 4; i++)
{
if(stCars[i].iPosition <= TRACK_LENGTH)
{
stCars[i].iPosition += fniRandGenMove();
}
printf("Car %d\n\t", stCars[i].iCarNumber);
for(j = 0; j < stCars[i].iPosition; j++)
{
printf("*");
}
if (stCars[i].iPosition > furthestCar.iPosition)
{
furthestCar.iPosition = stCars[i].iPosition;
furthestCar.iCarNumber = stCars[i].iCarNumber;
}
printf("\n");
}
system("PAUSE");
system("CLS");
} while(furthestCar.iPosition < TRACK_LENGTH);
printf("The winning car is #%d.\n", furthestCar.iCarNumber);
}

C - how to read color of a screen pixel (FAST)? (in Windows)

So I am looking for a way to read a color of a screen pixel in C code.
I already found implementation in C for *nix (which uses X11/Xlib library, that as I understood is for *nix systems only) and I tried the code on a linux machine, and it ran pretty fast (it reads 8K of pixels in about 1 second).
Here's the code in C that I've found and forked:
#include <X11/Xlib.h>
void get_pixel_color (Display *d, int x, int y, XColor *color)
{
XImage *image;
image = XGetImage (d, RootWindow (d, DefaultScreen (d)), x, y, 1, 1, AllPlanes, XYPixmap);
color->pixel = XGetPixel (image, 0, 0);
XFree (image);
XQueryColor (d, DefaultColormap(d, DefaultScreen (d)), color);
}
// Your code
XColor c;
get_pixel_color (display, 30, 40, &c);
printf ("%d %d %d\n", c.red, c.green, c.blue);
And I was looking for equivalent solution for Windows as well.
I came across this code (I've put the code about reading screen pixel in a 'for' loop):
FARPROC pGetPixel;
HINSTANCE _hGDI = LoadLibrary("gdi32.dll");
if(_hGDI)
{
pGetPixel = GetProcAddress(_hGDI, "GetPixel");
HDC _hdc = GetDC(NULL);
if(_hdc)
{
int i;
int _red;
int _green;
int _blue;
COLORREF _color;
ReleaseDC(NULL, _hdc);
for (i=0;i<8000;i++)
{
_color = (*pGetPixel) (_hdc, 30 ,40);
_red = GetRValue(_color);
_green = GetGValue(_color);
_blue = GetBValue(_color);
}
ReleaseDC(NULL, _hdc);
printf("Red: %d, Green: %d, Blue: %d", _red, _green, _blue);
}
FreeLibrary(_hGDI);
(using gdi32.dll and windows.h...)
and the 'for' portion of the code (where we read 8K of pixels) runs ALOT slower than the solution in C.
it takes 15 seconds to finish compared to 1 second with X11/Xlib.h library!
So, how can I make it better? or there is any other better and FASTER implementation to read pixel's colors with C code in Windows machine?
Thanks ahead!
I would suggest using loop unwinding. Basically, what this does is execute multiple cycles of your loop in a single iteration:
// Loop the equivalent of `n` cycles, ignoring the least significant bit
for (unsigned int i = 0; i < (n & ~0x01); i += 2)
{
do_some_operation(i);
do_some_operation(i + 1);
}
// Perform the last cycle manually, if one needs to be completed
if (n & 0x01)
{
do_some_operation(n - 1);
}
In this code, the loop ignores the least significant bit of n (which determines the parity of n) so that we are safe to increment i by 2 and perform the equivalent of 2 cycles in just 1 cycle, meaning that this loop is ~2 times faster than a conventional for (unsigned int i = 0; i < n; i++) loop. The final if statement checks the parity of n. If n is odd, the last cycle of the loop is performed.
Of course, this could be reimplemented to increment i by more than 2, but this would become increasingly complex. There is also an alternative to this, Duff's Device. It is basically the same idea, but uses a switch/case block.
After many tests, I've found that just about /anything/ you do to read pixels off the screen in windows using the GDI takes ~16ms (or about 1 frame) whether it is reading a single pixel, or reading even a small area with BitBlt. There doesn't seem to be any clear solution. I will be experimenting with the media libraries to see if I can get anywhere, but the Internet is pretty sure doing anything like this in Windows is just an awful mess, and really terrible things have to be done to do things like VNC or Fraps.

Pruning short line segments from edge detector output?

I am looking for an algorithm to prune short line segments from the output of an edge detector. As can be seen in the image (and link) below, there are several small edges detected that aren't "long" lines. Ideally I'd like just the 4 sides of the quadrangle to show up after processing, but if there are a couple of stray lines, it won't be a big deal... Any suggestions?
Image Link
Before finding the edges pre-process the image with an open or close operation (or both), that is, erode followed by dilate, or dilate followed by erode. this should remove the smaller objects but leave the larger ones roughly the same.
I've looked for online examples, and the best I could find was on page 41 of this PDF.
I doubt that this can be done with a simple local operation. Look at the rectangle you want to keep - there are several gaps, hence performing a local operation to remove short line segments would probably heavily reduce the quality of the desired output.
In consequence I would try to detect the rectangle as important content by closing the gaps, fitting a polygon, or something like that, and then in a second step discard the remaining unimportant content. May be the Hough transform could help.
UPDATE
I just used this sample application using a Kernel Hough Transform with your sample image and got four nice lines fitting your rectangle.
In case somebody steps on this thread, OpenCV 2.x brings an example named squares.cpp that basically nails this task.
I made a slight modification to the application to improve the detection of the quadrangle
Code:
#include "highgui.h"
#include "cv.h"
#include <iostream>
#include <math.h>
#include <string.h>
using namespace cv;
using namespace std;
void help()
{
cout <<
"\nA program using pyramid scaling, Canny, contours, contour simpification and\n"
"memory storage (it's got it all folks) to find\n"
"squares in a list of images pic1-6.png\n"
"Returns sequence of squares detected on the image.\n"
"the sequence is stored in the specified memory storage\n"
"Call:\n"
"./squares\n"
"Using OpenCV version %s\n" << CV_VERSION << "\n" << endl;
}
int thresh = 70, N = 2;
const char* wndname = "Square Detection Demonized";
// helper function:
// finds a cosine of angle between vectors
// from pt0->pt1 and from pt0->pt2
double angle( Point pt1, Point pt2, 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);
}
// returns sequence of squares detected on the image.
// the sequence is stored in the specified memory storage
void findSquares( const Mat& image, vector<vector<Point> >& squares )
{
squares.clear();
Mat pyr, timg, gray0(image.size(), CV_8U), gray;
// karlphillip: dilate the image so this technique can detect the white square,
Mat out(image);
dilate(out, out, Mat(), Point(-1,-1));
// then blur it so that the ocean/sea become one big segment to avoid detecting them as 2 big squares.
medianBlur(out, out, 3);
// down-scale and upscale the image to filter out the noise
pyrDown(out, pyr, Size(out.cols/2, out.rows/2));
pyrUp(pyr, timg, out.size());
vector<vector<Point> > contours;
// find squares only in the first color plane
for( int c = 0; c < 1; c++ ) // was: c < 3
{
int ch[] = {c, 0};
mixChannels(&timg, 1, &gray0, 1, ch, 1);
// try several threshold levels
for( int l = 0; l < N; l++ )
{
// hack: use Canny instead of zero threshold level.
// Canny helps to catch squares with gradient shading
if( l == 0 )
{
// apply Canny. Take the upper threshold from slider
// and set the lower to 0 (which forces edges merging)
Canny(gray0, gray, 0, thresh, 5);
// dilate canny output to remove potential
// holes between edge segments
dilate(gray, gray, Mat(), Point(-1,-1));
}
else
{
// apply threshold if l!=0:
// tgray(x,y) = gray(x,y) < (l+1)*255/N ? 255 : 0
gray = gray0 >= (l+1)*255/N;
}
// find contours and store them all as a list
findContours(gray, contours, CV_RETR_LIST, CV_CHAIN_APPROX_SIMPLE);
vector<Point> approx;
// test each contour
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);
// square contours should have 4 vertices after approximation
// relatively large area (to filter out noisy contours)
// and be convex.
// 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++ )
{
// find the maximum cosine of the angle between joint edges
double cosine = fabs(angle(approx[j%4], approx[j-2], approx[j-1]));
maxCosine = MAX(maxCosine, cosine);
}
// if cosines of all angles are small
// (all angles are ~90 degree) then write quandrange
// vertices to resultant sequence
if( maxCosine < 0.3 )
squares.push_back(approx);
}
}
}
}
}
// the function draws all the squares in the image
void drawSquares( Mat& image, const vector<vector<Point> >& squares )
{
for( size_t i = 1; i < squares.size(); i++ )
{
const Point* p = &squares[i][0];
int n = (int)squares[i].size();
polylines(image, &p, &n, 1, true, Scalar(0,255,0), 3, CV_AA);
}
imshow(wndname, image);
}
int main(int argc, char** argv)
{
if (argc < 2)
{
cout << "Usage: ./program <file>" << endl;
return -1;
}
static const char* names[] = { argv[1], 0 };
help();
namedWindow( wndname, 1 );
vector<vector<Point> > squares;
for( int i = 0; names[i] != 0; i++ )
{
Mat image = imread(names[i], 1);
if( image.empty() )
{
cout << "Couldn't load " << names[i] << endl;
continue;
}
findSquares(image, squares);
drawSquares(image, squares);
imwrite("out.jpg", image);
int c = waitKey();
if( (char)c == 27 )
break;
}
return 0;
}
The Hough Transform can be a very expensive operation.
An alternative that may work well in your case is the following:
run 2 mathematical morphology operations called an image close (http://homepages.inf.ed.ac.uk/rbf/HIPR2/close.htm) with a horizontal and vertical line (of a given length determined from testing) structuring element respectively. The point of this is to close all gaps in the large rectangle.
run connected component analysis. If you have done the morphology effectively, the large rectangle will come out as one connected component. It then only remains iterating through all the connected components and picking out the most likely candidate that should be the large rectangle.
Perhaps finding the connected components, then removing components with less than X pixels (empirically determined), followed by dilation along horizontal/vertical lines to reconnect the gaps within the rectangle
It's possible to follow two main techniques:
Vector based operation: map your pixel islands into clusters (blob, voronoi zones, whatever). Then apply some heuristics to rectify the segments, like Teh-Chin chain approximation algorithm, and make your pruning upon vectorial elements (start, endpoint, length, orientation and so on).
Set based operation: cluster your data (as above). For every cluster, compute principal components and detect lines from circles or any other shape by looking for clusters showing only 1 significative eigenvalue (or 2 if you look for "fat" segments, that could resemble to ellipses). Check eigenvectors associated with eigenvalues to have information about orientation of the blobs, and make your choice.
Both ways could be easily explored with OpenCV (the former, indeed, falls under "Contour analysis" category of algos).
Here is a simple morphological filtering solution following the lines of #Tom10:
Solution in matlab:
se1 = strel('line',5,180); % linear horizontal structuring element
se2 = strel('line',5,90); % linear vertical structuring element
I = rgb2gray(imread('test.jpg'))>80; % threshold (since i had a grayscale version of the image)
Idil = imdilate(imdilate(I,se1),se2); % dilate contours so that they connect
Idil_area = bwareaopen(Idil,1200); % area filter them to remove the small components
The idea is to basically connect the horizontal contours to make a large component and filter by an area opening filter later on to obtain the rectangle.
Results:

Resources