Difference between revisions of "VCSBC4018 vision board"

From AIRWiki
Jump to: navigation, search
(Part 5: Vl library)
(Part 6: Example Program)
 
(11 intermediate revisions by the same user not shown)
Line 170: Line 170:
  
 
putting instead of 352 the id of the window.
 
putting instead of 352 the id of the window.
 +
 +
== '''Part 6: Example Program''' ==
 +
Here is an example of a program that track an object [[Media:Traking.zip]].
 +
 +
To start correctly the program is needed to start paunch the software on the camera and to open the VL client on the PC. At start the program wait until the user select an object with the mouse and than it start to track it using histograms.
 +
 +
Here is the program code with comments:
 +
 +
#include <vcrt.h>
 +
#include <vclib.h>
 +
#include <macros.h>
 +
#include <sysvar.h>
 +
#include <flib.h>
 +
#include "vl.h"
 +
#define LUNG 30 //Initial tracking window with
 +
#define CENTRE_DISTANCE 40 //Maximum distance to search best histogram
 +
#define VX 4 //Step to enlarge tracking window on x axis
 +
#define VY 4 //Step to enlarge tracking window on y axis
 +
#define MINX 16 //Minimum track window dimension
 +
#define MINY 16 //Minimum track window dimension
 +
void mouseFunc(int, int, int, int, void*); //Mouse callback function
 +
void drawRect(image* i, int x1, int y1, int x2, int y2, int color);
 +
void calcHist(image* i, U32* h, int x1, int y1, int x2, int y2);
 +
float compHist(U32* h1, U32 *h2);
 +
int x1, x2, y1, y2, waitSelected = 0; //Coordinates of tracking rectangle
 +
int main(void)
 +
{
 +
image i;
 +
float vmax, v;
 +
int x, y, xmax, ymax;
 +
U32 h1[256], h2[256];
 +
        //Init licence of vclib
 +
init_licence("LT307EB4FAC1");
 +
 +
        //Start live mode
 +
vmode(vmLive);
 +
 +
        //Set the page to use VL lib
 +
ScrSetPhysPage((int)ScrGetPhysPage + 1);
 +
ScrSetLogPage((int)ScrGetPhysPage);
 +
        //Assign new image starting from ScrLogPage
 +
ImageAssign(&i, ScrByteAddr(0 , 0), DX, DY, ScrGetPitch);
 +
 +
        //Create new numbered window
 +
if (vlNumberedWindow(352) != VL_NO_ERROR)
 +
return 1;
 +
 +
        //Set new mouse callback function
 +
vlSetMouseCallback(352, mouseFunc, NULL);
 +
 +
printf("Select the object to track\n");
 +
 +
        //Loop that wait until the user select an object
 +
for (; vlWaitKey(352, 10) != 'q' && !waitSelected;)
 +
{
 +
                //Take a new picture from the camera
 +
tpict();
 +
 +
                //Show the image in ScrLogPage
 +
if (vlShowImage(352) != VL_NO_ERROR)
 +
return 1;
 +
 +
                //Seach for new mouse events
 +
searchForEvents();
 +
                //If the user press 'q' break
 +
if(kbhit() && rs232rcv() == 'q')
 +
break;
 +
}
 +
 +
        //Draw a rectangle around the object selected
 +
drawRect(&i, x1, y1, x2, y2, 0xFF);
 +
        //Show the image
 +
if (vlShowImage(352) != VL_NO_ERROR)
 +
return 1;
 +
        //Calc the histogram of the object selected
 +
calcHist(&i, h1, x1, y1, x2, y2);
 +
 +
        //Tracking loop
 +
for (; 1;)
 +
{
 +
tpict();
 +
 +
                //vmax contains the maximun macching value between the several histograms
 +
vmax = -9999999;
 +
for(y = y1 - CENTRE_DISTANCE; y < y1 + CENTRE_DISTANCE; y += 2)
 +
{
 +
for(x = x1 + y % 4 - CENTRE_DISTANCE; x < x1 + CENTRE_DISTANCE; x += 4)
 +
{
 +
                                //If a value of the tracking window exceeded the total image don't consider it
 +
if ((x >= DX) || (y >= DY) || (x < 0) || (y < 0))
 +
{
 +
continue;
 +
}
 +
 +
                                //Calc the histogram in the new position
 +
calcHist(&i, h2, x, y, x + x2 - x1, y + y2 - y1);
 +
 +
                                //Compare the first histogram with the new
 +
v = compHist(h1, h2);
 +
 +
                                //If the histogram match well save the coordinates
 +
if (v > vmax)
 +
{
 +
vmax = v;
 +
xmax = x;
 +
ymax = y;
 +
}
 +
}
 +
}
 +
 +
                //Calc the new tracking window coordinates
 +
x2 = xmax + x2 - x1;
 +
y2 = ymax + y2 - y1;
 +
x1 = xmax;
 +
y1 = ymax;
 +
 +
//Resize histogram rectangle
 +
calcHist(&i, h2, x1 + VX / 2, y1, x2, y2);
 +
v = compHist(h1, h2);
 +
if (v < vmax)
 +
{
 +
vmax = v;
 +
if (x2 - x1 > MINX)
 +
x1 += VX / 2;
 +
}
 +
calcHist(&i, h2, x1 - VX / 2, y1, x2, y2);
 +
v = compHist(h1, h2);
 +
if (v > vmax)
 +
{
 +
vmax = v;
 +
x1 -= VX / 2;
 +
}
 +
calcHist(&i, h2, x1, y1, x2 + VX / 2, y2);
 +
v = compHist(h1, h2);
 +
if (v > vmax)
 +
{
 +
vmax = v;
 +
x2 += VX / 2;
 +
}
 +
calcHist(&i, h2, x1, y1, x2 - VX / 2, y2);
 +
v = compHist(h1, h2);
 +
if (v > vmax)
 +
{
 +
vmax = v;
 +
if (x2 - x1 > MINX)
 +
x2 -= VX / 2;
 +
}
 +
calcHist(&i, h2, x1, y1 - VY / 2, x2, y2);
 +
v = compHist(h1, h2);
 +
if (v > vmax)
 +
{
 +
vmax = v;
 +
y1 -= VY / 2;
 +
}
 +
calcHist(&i, h2, x1, y1 + VY / 2, x2, y2);
 +
v = compHist(h1, h2);
 +
if (v > vmax)
 +
{
 +
vmax = v;
 +
if (y2 - y1 > MINY)
 +
y1 += VY / 2;
 +
}
 +
calcHist(&i, h2, x1, y1, x2, y2 + VY / 2);
 +
v = compHist(h1, h2);
 +
if (v > vmax)
 +
{
 +
vmax = v;
 +
y2 += VY / 2;
 +
}
 +
calcHist(&i, h2, x1, y1, x2, y2 - VY / 2);
 +
v = compHist(h1, h2);
 +
if (v > vmax)
 +
{
 +
vmax = v;
 +
if (y2 - y1 > MINY)
 +
y2 -= VY / 2;
 +
}
 +
 +
                //Draw rectangle around new area
 +
drawRect(&i, x1, y1, x2, y2, 0xFF);
 +
 +
                //Show the image
 +
if (vlShowImage(352) != VL_NO_ERROR)
 +
return 1;
 +
                //Search for new mouse event
 +
searchForEvents();
 +
if(kbhit() && rs232rcv() == 'q')
 +
break;
 +
}
 +
 +
        //Destroy window
 +
if (vlDestroyWindows(352) != VL_NO_ERROR)
 +
return 1;
 +
 +
        //Stop live mode
 +
vmode(vmStill);
 +
 +
return 0;
 +
}
 +
 +
//Mouse callback function
 +
void mouseFunc(int event, int x, int y, int flags, void* param)
 +
{
 +
if (event == VL_EVENT_LBUTTONUP)
 +
{
 +
                //Create the rectangle arround where the user clicked
 +
x1 = x - LUNG / 2;
 +
y1 = y - LUNG / 2;
 +
x2 = x + LUNG / 2;
 +
y2 = y + LUNG / 2;
 +
waitSelected = 1;
 +
}
 +
}
 +
 +
//Draw new rectangle in image i
 +
void drawRect(image* i, int x1, int y1, int x2, int y2, int color)
 +
{
 +
int x, y;
 +
 +
if (x1 > x2)
 +
{
 +
x = x1;
 +
x1 = x2;
 +
x2 = x;
 +
}
 +
if (y1 > y2)
 +
{
 +
y = y1;
 +
y1 = y2;
 +
y2 = y;
 +
}
 +
 +
for (x = 0; x1 + x <= x2; x++)
 +
{
 +
ImageSetPixel(i, x1 + x, y1, color);
 +
}
 +
for (x = 0; x1 + x <= x2; x++)
 +
{
 +
ImageSetPixel(i, x1 + x, y2, color);
 +
}
 +
for (y = 0; y1 + y <= y2; y++)
 +
{
 +
ImageSetPixel(i, x1, y1 + y, color);
 +
}
 +
for (y = 0; y1 + y <= y2; y++)
 +
{
 +
ImageSetPixel(i, x2, y1 + y, color);
 +
}
 +
}
 +
 +
//Create new histogram in image i in the rectangle with coordinates (x1, y1), (x2, y2)
 +
void calcHist(image* i, U32* h, int x1, int y1, int x2, int y2)
 +
{
 +
int x, y;
 +
 +
for (x = 0; x < 256; x++)
 +
h[x] = 0;
 +
 +
for (x = x1; x <= x2; x++)
 +
{
 +
for (y = y1; y <= y2; y++)
 +
{
 +
h[(*((U8 *)((long)((i)->st+(x)+(y)*(i)->pitch))))]++;
 +
}
 +
}
 +
}
 +
 +
//Compare histogram using mean square error
 +
float compHist(U32* h1, U32 *h2)
 +
{
 +
int tot = 0, c = 0, sum = 0;
 +
 +
for (; c < 256; c++)
 +
{
 +
tot += (h1[c] - h2[c]) * (h1[c] - h2[c]);
 +
sum += h1[c] + h2[c];
 +
}
 +
 +
return - tot / sum;
 +
}
 +
 +
Here are some video example of the program result:
 +
 +
{{#ev:youtube|Nz_62HHkQHA}}
 +
 +
*[http://www.youtube.com/watch?v=Nz_62HHkQHA External link]
 +
 +
{{#ev:youtube|jDPpNI4YrKA}}
 +
 +
*[http://www.youtube.com/watch?v=jDPpNI4YrKA External link]
 +
 +
{{#ev:youtube|wBm5ijRGYok}}
 +
 +
*[http://www.youtube.com/watch?v=wBm5ijRGYok External link]

Latest revision as of 11:08, 2 August 2010

This tutorial explains how to use the camera board VCSBC4018.

This camera board mounts a TMS320C64xx TI processor working at 40MHZ. The camera sensor can take images with a resolution of 640 x 480 pixels. The board is equiped with a 100 Mbit Ethernet that allows to comunicate with a PC, 32 MB RAM and 4 MB flash EPROM. Power supply: 12~14V.

Part 1: HW connection

First of all you need to connect the LAN jumper (J4) and power jumper (J3).

Jump.jpg

The photo above represents a generic board, in fact the VCSBC4018 doesn't have the J6 jumper.

On the other hand, the photo below shows the real board with the two jumpers connected.

Collegamenti on board.jpg

The power (12~24V) must be connected to the red cable of J3 and the GND to the balck cable of the same connector. At the end, the RJ-45 connector must be plugged into PC LAN port.

Part 2: SW installation

Now it'time to install the necessary PC software. The software we are going to use can be used only on Microsoft Windows. To begin you have to download Code Composer Studio from Texas Instrument web site (http://focus.ti.com/docs/toolsw/folders/print/ccstudio.html). To be able to download it have to be loged in. The current software viersion is 4.1.2, this tutoria will continue using this particular version. After that you must run the setup program. So choose the installation directory, for example C:\ti. Immagine8little.jpg

Now continue pressing "Next" until the setup program asks for the product configuration, choose "Platinum Edition". Immagine4.jpg

When The setup program asks for the components to install : check the “Code Composer Studio v4” box for a complete install. Immagine6.jpg

In this way the developement tool is installed. You can use it for free for a mounth. After that you can register on web and you can use it for free for other two mounth.

Now it's time to install the compiler "Code Generation Tools". You can download it from the TI site (https://www-a.ti.com/downloads/sds_support/TICodegenerationTools/download.htm) like before you have to be loged in to download the software. The current version is 6.0.23. So launch the setup program. During the installation choose "Typical Install" Immagine11.jpg

and when asked choose the same directory of CCS4 (the folder name should contain no space). Immagine12.jpg

The camera productor developed a library to help the user to take images and work on those. The library can be downloaded on http://www.vision-components.com/ following this links: Services & Support -> Download Center -> Software -> VC Libraries. So download the version for Code Composer 4.x users and launch the installation process "TI-VCRT5XX_VCLIB3XX_CCS4_Setup.exe". Install the VC library to the same folder as CCS4 (for example C:\ti).

Now you are abble to write the you first program for the camera.

Part 3: Create the first project

Now it's time to create the first CCS4 project.

With the installation of VC Library, Vision Components provides a template CCS4 project, containing all the necessary compiler and linker settings to create programs which will run properly on camera.

Then run CCS 4. The program asks you to choose a “workspace”, the place where all your CCS 4 projects will be saved. The template project was installed in the \myprojects folder of the install folder. If you want to use this folder for your future projects too, choose it as workspace, for example C:\ti\myprojects, and select “OK”. A windows will open to ask you the licence. Select evaluetion version to use the software 30 days for free.

Import the template CCS4 project provided by VC. For this, go to menu Project->Import Existing CCS/CCE Eclipse Project. Browse to your workspace and choose thefolder C:\ti\myprojects. Select the project vcproject that appears in the list. Click on Finish.

Immagine14.jpg

The project vcproject appears in the left column. It shows the include folders, a sample program “hello.c” and the link command file which contains the libraries to be linked.

To change the setting of the project right-click on the project folder on the left and choose "Build Properties". Click on “CCS Build” in the left column. Now you could have the following settings:

- Device Variant: Generic C64XX device

- Code Generation Tools: version 6.0.23 (if the version doesn’t appear in the list, click on “More…” and in the dialog indicate the CGTools installation folder)

- Linker command file: ccr.cmd

- Runtime Support Library: from VCRT 5.29, the rts6400.lib is supported for compilation with C64xx processors. But as it’s already linked in the linker command file (ccr.cmd), the field has to be empty!

Immagine15.jpg

If you click on “C/C++ Build” in the left column, and choose the “Buils Settings” tab, you can give the name of the executable program. Leave “.out” as extension.

Immagine16.jpg


Now it's time to compile the project. To do this you can click on the button "Build active project" on the top bar. Immagine17.jpg

The compiler warning: “entry point other than _c_int00 specified” is not relevant as VCRT uses a different entry point.

According to the build options two output files “new.out” and “new.msf” are generated through the compilation process. These files are stored in the “send” folder of your CCS4 project folder.

Part 4: Program execution

Before to exec the program on the camera you have to connect the camera to the PC by the LAN cable. Now go to TCP/IP setting and set your IP and mask on the nektwork interface where you had connected the camera. The IP you have to set must be 192.168.0.X where X != 65 and the mask 255.255.255.0. The default IP of the camera is 192.168.0.65.

Immagine18.jpg

Now you can use the camera shell with a PC terminal, in this tutorial we are going to use Tera Term.

Start Tera Term, set the IP host 192.168.0.65, select the Telnet service and press OK.

Immagine19.jpg

When it asks for the password press enter and the camera mast reply like in the image below.

Immagine20.jpg

If you want to know the shell command consult the respectiv manual.

It's now time to upload the program on the camera. You can do this by shell or by FTP. In this tutorial we use the FTP mode.

Download Total Commander (other FTP don't work very well with the camera), install it and launch it. Set the FTP like below.

Immagine21.jpg

Press "Anonymous login (e-mail address as password)" and set "support@vision-comp.com".

When you are connected with the camera you upload the program. So, take the program with extension .out from the folder "send" in your CCS4 project and upload it on "\fd:" via FTP. After that you can run the program entering the name of the program via Tera Term.

Part 5: Vl library

VL library is a little library that helps the developer to create new programs for the camera. To use it you have to include in the project the file vl.h Media:Vl.zip. The library allow to create new windows, show images inside and take mouse events like in OpenCV. To use the library you must set the physic and log page in this way:

ScrSetPhysPage((int)ScrGetPhysPage + 1);

ScrSetLogPage((int)ScrGetPhysPage);

Theese are the funcions that can be used:

int vlNumberedWindow(int id)

this function creates a new numere window. The parameter id is the number of the window. Note that the integer id is used from the library as TCP port so is suggested to use id > 256. If no error are occorred VL_NO_ERROR is returned.

int vlShowImage(int id)

this function shows the image that is in the log page in the id window. If no error are occorred VL_NO_ERROR is returned.

int vlDestroyWindows(int id)

this function closes the id window. If no error are occorred VL_NO_ERROR is returned.

void vlSetMouseCallback(int id, void (*mouseCallBackFunc)(int, int, int, int, void*), void* param)

this function sets the callback function for the mouse events for the id window. The parameter param is a parameter that can be passed to the callback function.

void searchForEvents()

this function must be called you need to search if some events are occorred. For example, if you have an infinity loop you could call the function inside the loop.

int vlWaitKey(int id, int delay)

this function works lick cvWaitKey. It waits delay milliseconds and if in that time any key have been pressed the function returns the pressed key.

To use this library you have to open on the PC linked to the camera the VLClient Media:VLClient.zip. It's nedded to have OpenCV installed, to open a client for each window and to modify the following code line:

serverAddr.sin_addr.s_addr = (long) inet_addr("192.168.0.65");

serverAddre.sin_addr.s_addr = (long) inet_addr("192.168.0.65");

putting instead of "192.168.0.65" the IP camera address

serverAddr.sin_port = htons((u_short) 352);

serverAddre.sin_port = htons((u_short) 352);

putting instead of 352 the id of the window.

Part 6: Example Program

Here is an example of a program that track an object Media:Traking.zip.

To start correctly the program is needed to start paunch the software on the camera and to open the VL client on the PC. At start the program wait until the user select an object with the mouse and than it start to track it using histograms.

Here is the program code with comments:

#include <vcrt.h>
#include <vclib.h>
#include <macros.h>
#include <sysvar.h>
#include <flib.h>
#include "vl.h"
#define LUNG 30 //Initial tracking window with
#define CENTRE_DISTANCE 40 //Maximum distance to search best histogram
#define VX 4 //Step to enlarge tracking window on x axis
#define VY 4 //Step to enlarge tracking window on y axis
#define MINX 16 //Minimum track window dimension
#define MINY 16 //Minimum track window dimension
void mouseFunc(int, int, int, int, void*); //Mouse callback function
void drawRect(image* i, int x1, int y1, int x2, int y2, int color);
void calcHist(image* i, U32* h, int x1, int y1, int x2, int y2);
float compHist(U32* h1, U32 *h2);
int x1, x2, y1, y2, waitSelected = 0; //Coordinates of tracking rectangle
int main(void)
{
	image i;
	float vmax, v;
	int x, y, xmax, ymax;
	U32 h1[256], h2[256];
       //Init licence of vclib
	init_licence("LT307EB4FAC1");
	
       //Start live mode
	vmode(vmLive);
	
       //Set the page to use VL lib
	ScrSetPhysPage((int)ScrGetPhysPage + 1);
	ScrSetLogPage((int)ScrGetPhysPage);
       //Assign new image starting from ScrLogPage
	ImageAssign(&i, ScrByteAddr(0 , 0), DX, DY, ScrGetPitch);
	
       //Create new numbered window
	if (vlNumberedWindow(352) != VL_NO_ERROR)
		return 1;
	
       //Set new mouse callback function
	vlSetMouseCallback(352, mouseFunc, NULL);
	
	printf("Select the object to track\n");
	
       //Loop that wait until the user select an object
	for (; vlWaitKey(352, 10) != 'q' && !waitSelected;)
	{
               //Take a new picture from the camera
		tpict();
		
               //Show the image in ScrLogPage
		if (vlShowImage(352) != VL_NO_ERROR)
			return 1;
		
               //Seach for new mouse events
		searchForEvents();
               //If the user press 'q' break
		if(kbhit() && rs232rcv() == 'q')
			break;
	}
	
       //Draw a rectangle around the object selected
	drawRect(&i, x1, y1, x2, y2, 0xFF);
       //Show the image
	if (vlShowImage(352) != VL_NO_ERROR)
		return 1;
       //Calc the histogram of the object selected
	calcHist(&i, h1, x1, y1, x2, y2);
	
       //Tracking loop
	for (; 1;)
	{
		tpict();
		
               //vmax contains the maximun macching value between the several histograms
		vmax = -9999999;
		for(y = y1 - CENTRE_DISTANCE; y < y1 + CENTRE_DISTANCE; y += 2)
		{
			for(x = x1 + y % 4 - CENTRE_DISTANCE; x < x1 + CENTRE_DISTANCE; x += 4)
			{
                               //If a value of the tracking window exceeded the total image don't consider it
				if ((x >= DX) || (y >= DY) || (x < 0) || (y < 0))
				{
					continue;
				}
				
                               //Calc the histogram in the new position
				calcHist(&i, h2, x, y, x + x2 - x1, y + y2 - y1);
				
                               //Compare the first histogram with the new
				v = compHist(h1, h2);
				
                               //If the histogram match well save the coordinates
				if (v > vmax)
				{
					vmax = v;
					xmax = x;
					ymax = y;
				}
			}
		}
		
               //Calc the new tracking window coordinates
		x2 = xmax + x2 - x1;
		y2 = ymax + y2 - y1;
		x1 = xmax;
		y1 = ymax;
		
		//Resize histogram rectangle
		calcHist(&i, h2, x1 + VX / 2, y1, x2, y2);
		v = compHist(h1, h2);
		if (v < vmax)
		{
			vmax = v;
			if (x2 - x1 > MINX)
				x1 += VX / 2;
		}
		calcHist(&i, h2, x1 - VX / 2, y1, x2, y2);
		v = compHist(h1, h2);
		if (v > vmax)
		{
			vmax = v;
			x1 -= VX / 2;
		}
		calcHist(&i, h2, x1, y1, x2 + VX / 2, y2);
		v = compHist(h1, h2);
		if (v > vmax)
		{
			vmax = v;
			x2 += VX / 2;
		}
		calcHist(&i, h2, x1, y1, x2 - VX / 2, y2);
		v = compHist(h1, h2);
		if (v > vmax)
		{
			vmax = v;
			if (x2 - x1 > MINX)
				x2 -= VX / 2;
		}
		calcHist(&i, h2, x1, y1 - VY / 2, x2, y2);
		v = compHist(h1, h2);
		if (v > vmax)
		{
			vmax = v;
			y1 -= VY / 2;
		}
		calcHist(&i, h2, x1, y1 + VY / 2, x2, y2);
		v = compHist(h1, h2);
		if (v > vmax)
		{
			vmax = v;
			if (y2 - y1 > MINY)
				y1 += VY / 2;
		}
		calcHist(&i, h2, x1, y1, x2, y2 + VY / 2);
		v = compHist(h1, h2);
		if (v > vmax)
		{
			vmax = v;
			y2 += VY / 2;
		}
		calcHist(&i, h2, x1, y1, x2, y2 - VY / 2);
		v = compHist(h1, h2);
		if (v > vmax)
		{
			vmax = v;
			if (y2 - y1 > MINY)
				y2 -= VY / 2;
		}
		
               //Draw rectangle around new area
		drawRect(&i, x1, y1, x2, y2, 0xFF);
		
               //Show the image
		if (vlShowImage(352) != VL_NO_ERROR)
			return 1;
               //Search for new mouse event
		searchForEvents();
		if(kbhit() && rs232rcv() == 'q')
			break;
	}
	
       //Destroy window
	if (vlDestroyWindows(352) != VL_NO_ERROR)
		return 1;
	
       //Stop live mode
	vmode(vmStill);
	
	return 0;
} 

//Mouse callback function
void mouseFunc(int event, int x, int y, int flags, void* param)
{
	if (event == VL_EVENT_LBUTTONUP)
	{
               //Create the rectangle arround where the user clicked
		x1 = x - LUNG / 2;
		y1 = y - LUNG / 2;
		x2 = x + LUNG / 2;
		y2 = y + LUNG / 2;
		waitSelected = 1;
	}
}

//Draw new rectangle in image i
void drawRect(image* i, int x1, int y1, int x2, int y2, int color)
{
	int x, y;
	
	if (x1 > x2)
	{
		x = x1;
		x1 = x2;
		x2 = x;
	}
	if (y1 > y2)
	{
		y = y1;
		y1 = y2;
		y2 = y;
	}
	
	for (x = 0; x1 + x <= x2; x++)
	{
		ImageSetPixel(i, x1 + x, y1, color);
	}
	for (x = 0; x1 + x <= x2; x++)
	{
		ImageSetPixel(i, x1 + x, y2, color);
	}
	for (y = 0; y1 + y <= y2; y++)
	{
		ImageSetPixel(i, x1, y1 + y, color);
	}
	for (y = 0; y1 + y <= y2; y++)
	{
		ImageSetPixel(i, x2, y1 + y, color);
	}
}

//Create new histogram in image i in the rectangle with coordinates (x1, y1), (x2, y2)
void calcHist(image* i, U32* h, int x1, int y1, int x2, int y2)
{
	int x, y;
	
	for (x = 0; x < 256; x++)
		h[x] = 0;
	
	for (x = x1; x <= x2; x++)
	{
		for (y = y1; y <= y2; y++)
		{
			h[(*((U8 *)((long)((i)->st+(x)+(y)*(i)->pitch))))]++;
		}
	}
}

//Compare histogram using mean square error
float compHist(U32* h1, U32 *h2)
{
	int tot = 0, c = 0, sum = 0;
	
	for (; c < 256; c++)
	{
		tot += (h1[c] - h2[c]) * (h1[c] - h2[c]);
		sum += h1[c] + h2[c];
	}
	
	return - tot / sum;
}

Here are some video example of the program result: