Processing Class/object variable stacking - class

So I have a problem that I've managed to fix before (by fluke) in simpler programs, but still don't know what the actual problem is.
I have created an class containing the following variables g1.display(tableHr, hrMeasure, 37, 10, 20,160, 0);. The problem is, when I run one object of the class it's all fine and a nice graph is created. Though when I run two objects of the class, the first graph in the program runs fine and the second one gets morphed out of proportion. Almost like variables are stacking or multiplying each other.
Anyone familiar with this problem?
The Main sketch's code:
Graph g1 = new Graph();
Button b1 = new Button();
TableRow hrMeasure;
TableRow spoMeasure;
TableRow tempMeasure;
Table tableHr;
Table tableSpo;
Table tableAbp;
Table tableResp;
Table tableTemp;
int i;
int border;
float p;
PFont font;
PFont font2;
String alarmColor;
void setup(){
font = loadFont("data/OpenSans-36.vlw");
textFont(font,36);
frameRate(15);
smooth(8);
size(1024,768);
tableHr = loadTable("testfile.csv", "header");
tableSpo = loadTable("testfile2.csv", "header");
tableAbp = loadTable("testfile3.csv", "header");
tableResp = loadTable("testfile4.csv", "header");
tableTemp = loadTable("testfile5.csv", "header");
}
void draw(){
retrieveData();
GUI();
relativeGraph();
buttons();
g1.display(tableHr, hrMeasure, 40, 15, 25,200,100);
// g1.display(tableSpo, spoMeasure, 37, 1, 3,160,2);
// g1.display(tableTemp, tempMeasure, 37, 1, 3,160,3);
// g1.display(tableHr, hrMeasure, 37, 13, 18,160,4);
// g1.display(tableHr, hrMeasure, 37, 13, 18,160,5);
}
//retrieving data from the csv file
void retrieveData(){
i++;
hrMeasure = tableHr.getRow(i);
spoMeasure = tableSpo.getRow(i);
tempMeasure = tableTemp.getRow(i);
}
Class:
class Graph {
int adjustment;
float p;
int greenRelative, yellowRelative, redRelative;
float[] measure = new float[1500000];
String alarmColor;
int timer, counter;
int greenTimer, yellowTimer, redTimer;
int graphHeight = 80;
int graphLength = 800;
void display(Table table, TableRow measurement, int average, int bound1, int bound2,int x, int y){
p = measurement.getFloat("value");
pushMatrix();
translate(width,0);
scale(-1,1);
for (int i = 0; i < table.getRowCount(); i++){
adjustment = width-table.getRowCount()-x; // adjustment to the x-coordinate, so every graph will start at 0
//if statement for green readings
if(measure[i] > average-bound1 && measure[i] < average+bound1){
stroke(0, 255, 0);
strokeWeight(1);
alarmColor = "green";
}else{
//if statement for yellow readings
if(measure[i] <= average-bound1 && measure[i] > average-bound2|| measure[i] >= average+bound1 && measure[i] < average+bound2){
stroke(255, 255, 0);
strokeWeight(1);
alarmColor = "yellow";
//else red
}else{stroke(255, 0, 0);
strokeWeight(1);
alarmColor = "red";
}}
line(i+adjustment, graphHeight-map(measure[i], average-bound1-bound2, 37, 0,graphHeight/2)+y, (i+1)+adjustment, graphHeight-map(measure[i+1], average-bound1-bound2, 37, 0,graphHeight/2)+y);
}
popMatrix();
for(int i=0; i < table.getRowCount(); i++){
measure[i] = measure[i+1];
measure[i+1] = p;
println(measure[i]);
}

Ensure you are using independent instances, for example:
Graph g1 = new Graph();
Graph g2 = new Graph();
then in draw():
g1.display(tableHr, hrMeasure, 40, 15, 25,200,100);
g2.display(tableSpo, spoMeasure, 37, 1, 3,160,2);
Full listing:
Graph g1 = new Graph();
Graph g2 = new Graph();
Graph g3 = new Graph();
Graph g4 = new Graph();
Graph g5 = new Graph();
Button b1 = new Button();
TableRow hrMeasure;
TableRow spoMeasure;
TableRow tempMeasure;
Table tableHr;
Table tableSpo;
Table tableAbp;
Table tableResp;
Table tableTemp;
int i;
int border;
float p;
PFont font;
PFont font2;
String alarmColor;
void setup(){
font = loadFont("data/OpenSans-36.vlw");
textFont(font,36);
frameRate(15);
smooth(8);
size(1024,768);
tableHr = loadTable("testfile.csv", "header");
tableSpo = loadTable("testfile2.csv", "header");
tableAbp = loadTable("testfile3.csv", "header");
tableResp = loadTable("testfile4.csv", "header");
tableTemp = loadTable("testfile5.csv", "header");
}
void draw(){
retrieveData();
GUI();
relativeGraph();
buttons();
g1.display(tableHr, hrMeasure, 40, 15, 25,200,100);
g2.display(tableSpo, spoMeasure, 37, 1, 3,160,2);
g3.display(tableTemp, tempMeasure, 37, 1, 3,160,3);
g4.display(tableHr, hrMeasure, 37, 13, 18,160,4);
g5.display(tableHr, hrMeasure, 37, 13, 18,160,5);
}
//retrieving data from the csv file
void retrieveData(){
i++;
hrMeasure = tableHr.getRow(i);
spoMeasure = tableSpo.getRow(i);
tempMeasure = tableTemp.getRow(i);
}
class Graph {
int adjustment;
float p;
int greenRelative, yellowRelative, redRelative;
float[] measure = new float[1500000];
String alarmColor;
int timer, counter;
int greenTimer, yellowTimer, redTimer;
int graphHeight = 80;
int graphLength = 800;
void display(Table table, TableRow measurement, int average, int bound1, int bound2,int x, int y){
p = measurement.getFloat("value");
pushMatrix();
translate(width,0);
scale(-1,1);
for (int i = 0; i < table.getRowCount(); i++){
adjustment = width-table.getRowCount()-x; // adjustment to the x-coordinate, so every graph will start at 0
//if statement for green readings
if(measure[i] > average-bound1 && measure[i] < average+bound1){
stroke(0, 255, 0);
strokeWeight(1);
alarmColor = "green";
}else{
//if statement for yellow readings
if(measure[i] <= average-bound1 && measure[i] > average-bound2|| measure[i] >= average+bound1 && measure[i] < average+bound2){
stroke(255, 255, 0);
strokeWeight(1);
alarmColor = "yellow";
//else red
}else{stroke(255, 0, 0);
strokeWeight(1);
alarmColor = "red";
}}
line(i+adjustment, graphHeight-map(measure[i], average-bound1-bound2, 37, 0,graphHeight/2)+y, (i+1)+adjustment, graphHeight-map(measure[i+1], average-bound1-bound2, 37, 0,graphHeight/2)+y);
}
popMatrix();
for(int i=0; i < table.getRowCount(); i++){
measure[i] = measure[i+1];
measure[i+1] = p;
println(measure[i]);
}

Related

Add percent to boxes of image after prediction?

I'm working with darknet and want to add the prediction in percent next to the label with darknet like this:
rather than the default like this:
Is there a way to do this? after you've run darknet it displays the probability that the label surrounding the object is the actual label. This is what i want to add to the image itself.
I figured out how to add it. I've added the code for anyone with the same question in the future so it's copy and paste. remember to re-make darknet afterwards.
We need to replace draw_directions function in darknet/src/image.c with the following:
void draw_detections(image im, detection *dets, int num, float thresh, char **names, image **alphabet, int classes)
{
int i,j;
for(i = 0; i < num; ++i){
char labelstr[4096] = {0};
int class = -1;
for(j = 0; j < classes; ++j){
if (dets[i].prob[j] > thresh){
if (class < 0) {
/* this line adds the percent to the image*/
sprintf(labelstr,"%s %f%%",names[j], (dets[i].prob[j]*100) );
class = j;
} else {
strcat(labelstr, ", ");
strcat(labelstr, names[j]);
}
printf("%s: %.0f%%\n", names[j], dets[i].prob[j]*100);
}
}
if(class >= 0){
int width = im.h * .006;
/*
if(0){
width = pow(prob, 1./2.)*10+1;
alphabet = 0;
}
*/
//printf("%d %s: %.0f%%\n", i, names[class], prob*100);
int offset = class*123457 % classes;
float red = get_color(2,offset,classes);
float green = get_color(1,offset,classes);
float blue = get_color(0,offset,classes);
float rgb[3];
//width = prob*20+2;
rgb[0] = red;
rgb[1] = green;
rgb[2] = blue;
box b = dets[i].bbox;
//printf("%f %f %f %f\n", b.x, b.y, b.w, b.h);
int left = (b.x-b.w/2.)*im.w;
int right = (b.x+b.w/2.)*im.w;
int top = (b.y-b.h/2.)*im.h;
int bot = (b.y+b.h/2.)*im.h;
if(left < 0) left = 0;
if(right > im.w-1) right = im.w-1;
if(top < 0) top = 0;
if(bot > im.h-1) bot = im.h-1;
draw_box_width(im, left, top, right, bot, width, red, green, blue);
if (alphabet) {
image label = get_label(alphabet, labelstr, (im.h*.03));
draw_label(im, top + width, left, label, rgb);
free_image(label);
}
if (dets[i].mask){
image mask = float_to_image(14, 14, 1, dets[i].mask);
image resized_mask = resize_image(mask, b.w*im.w, b.h*im.h);
image tmask = threshold_image(resized_mask, .5);
embed_image(tmask, im, left, top);
free_image(mask);
free_image(resized_mask);
free_image(tmask);
}
}
}
}

When running a method of a class I get a 'unexpected token: (' error message

I am new to java and I am using processing. I am just learning to how use classes is java and I am getting confusing error messages when I run a method. the error message is 'unexpected token: (' the error as at the p.setPieces(pawn, white); line
here is my code:
int ranks = 8;
int files = 8;
int spacing;
// set the values for all the pieces and colors
int empty = 0;
int pawn = 1;
int knight = 2;
int bishop = 3;
int rook = 4;
int queen = 5;
int king = 6;
int white = 8;
int black = 16;
Piece p = new Piece();
p.setPiece(pawn, white);
void setup() {
size(600, 600);
spacing = width / ranks;
}
void draw() {
background(0);
// draw the board
for (int i = 0; i < ranks; i++) {
for (int j = 0; j < files; j++) {
if ((i + j) % 2 == 0) {
noStroke();
fill(255);
rect(i * spacing, j * spacing, spacing, spacing);
} else {
noStroke();
fill(0);
rect(i * spacing, j * spacing, spacing, spacing);
}
}
}
}
and then in a different file I have:
class Piece {
// make variables for color and type of a piece
int pieceType;
int pieceColor;
// set up type and color
void setPiece(int Type, int Color) {
pieceType = Type;
pieceColor = Color;
}
}
As khelwood and luk2302 mentioned, simply move p.setPiece(pawn, white); in setup() (preferably after size()):
int ranks = 8;
int files = 8;
int spacing;
// set the values for all the pieces and colors
int empty = 0;
int pawn = 1;
int knight = 2;
int bishop = 3;
int rook = 4;
int queen = 5;
int king = 6;
int white = 8;
int black = 16;
Piece p = new Piece();
void setup() {
size(600, 600);
spacing = width / ranks;
p.setPiece(pawn, white);
}
void draw() {
background(0);
// draw the board
for (int i = 0; i < ranks; i++) {
for (int j = 0; j < files; j++) {
if ((i + j) % 2 == 0) {
noStroke();
fill(255);
rect(i * spacing, j * spacing, spacing, spacing);
} else {
noStroke();
fill(0);
rect(i * spacing, j * spacing, spacing, spacing);
}
}
}
}
class Piece {
// make variables for color and type of a piece
int pieceType;
int pieceColor;
// set up type and color
void setPiece(int Type, int Color) {
pieceType = Type;
pieceColor = Color;
}
}
When using "active" mode (e.g. setup()/draw()) you can only declare variables (at the top), but not use them directly in the main block of code. You need to reference them within a function.

How to show Output as a text instead of number?

I use this code for print number 0 to 11 in a button:
colorize_combo = gtk_combo_box_text_new_with_entry();
for (int i = 0; i <= 2; i += 1)
gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(colorize_combo), g_strdup_printf("%d", i));
gtk_combo_box_set_active(GTK_COMBO_BOX(colorize_combo), 11);
gtk_table_attach_defaults(GTK_TABLE(table), colorize_combo, 0, 1, 17, 18);
I use applyColorMap(unsharp, dstt, type_color) in opencv and I have 12 types color. these types color show up as numbers (0 to 11) . I want to show output as a "text" instead of "number" in my button. I can change types color with "color" button.
I just want to change for example, "0" to "AUTUMN", "1" to "BONE" , .... If you use gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(colorize_combo), g_strdup_printf("AUTUMN", 0)); that show up "0" to "AUTUMN" but I want all of them show up just with one gtk_combo_box_text_append_text.
I want to show output as a "text" instead of "number" in my button.
"AUTUMN" instead of "0"
"BONE" instead of "1"
"JET" instead of "2"
.
.
.
.
"PARULA" instead of "11"
What ideas on how to solve this task would you suggest? Or on what resource on the internet can I find help?
this is a part of my c++ code:
void incdec2(GtkWidget *widget, const gchar *mode)
{
else if (!g_strcmp0(mode, "colorized"))
{
if (gtk_image_get_pixbuf(GTK_IMAGE(img4)) == NULL)
return;
int type_color = atoi(gtk_combo_box_text_get_active_text(GTK_COMBO_BOX_TEXT(colorize_combo)));
vector< Vec4i > hierarchy;
int largest_contour_index = 0;
int largest_area = 0;
vector< vector <Point> > contours1;
Mat alpha(src1.size(), CV_8UC1, Scalar(0));
normalize(alpha, alpha, 0, 250, NORM_MINMAX, CV_8UC3);
findContours(thresh, contours1, hierarchy, CV_RETR_EXTERNAL, CV_CHAIN_APPROX_SIMPLE); // Find the contours in the image
for (int i = 0; i< contours1.size(); i++) // iterate through each contour.
{
double a = contourArea(contours1[i], false); // Find the area of contour
if (a>largest_area){
largest_area = a;
largest_contour_index = i; //Store the index of largest contour
}
}
drawContours(alpha, contours1, largest_contour_index, Scalar(255), CV_FILLED, 8, hierarchy);
applyColorMap(unsharp, dstt, type_color);
split(dstt, rgb);
Mat rgbe[4] = { rgb[0], rgb[1], rgb[2], alpha };
merge(rgbe, 4, im_color);
imwrite("Colorized Image.png", im_color);
gtk_image_set_from_file(GTK_IMAGE(img4), "Colorized Image.png");
}
}
int main(int argc, char *argv[])
{
.
.
.
.
.
colorize_combo = gtk_combo_box_text_new_with_entry();
for (int i = 0; i <= 11; i += 1)
gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(colorize_combo), g_strdup_printf("%d", i));
//gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(colorize_combo), g_strdup_printf("AUTUMN", 0));
//gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(colorize_combo), g_strdup_printf("BONE", 1));
// gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(colorize_combo), g_strdup_printf("JET", 2));
//gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(colorize_combo), g_strdup_printf("WINTER", 3));
//gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(colorize_combo), g_strdup_printf("RAINBOW", 4));
//gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(colorize_combo), g_strdup_printf("OCEAN", 5));
//gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(colorize_combo), g_strdup_printf("SUMMER", 6));
//gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(colorize_combo), g_strdup_printf("SPRING", 7));
//gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(colorize_combo), g_strdup_printf("COOL", 8));
//gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(colorize_combo), g_strdup_printf("HSV", 9));
//gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(colorize_combo), g_strdup_printf("PINK", 10));
//gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(colorize_combo), g_strdup_printf("HOT", 11));
//gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(colorize_combo), g_strdup_printf("PARULA", 12));
gtk_combo_box_set_active(GTK_COMBO_BOX(colorize_combo), 11);
gtk_table_attach_defaults(GTK_TABLE(table), colorize_combo, 0, 1, 17, 18);
but13 = bold_img_button("Color", "E:/Works for Gov Project/DOC/GUI/logogui1/colorize243.png");
gdk_color_parse("#50a0ff", &color);
gtk_widget_modify_bg(but13, GTK_STATE_NORMAL, &color);
gtk_table_attach_defaults(GTK_TABLE(table), but13, 1, 2, 17, 18);
g_signal_connect(G_OBJECT(but13), "clicked", G_CALLBACK(incdec2), "colorized");
.
.
.
.
}
For example, I edit my loop as:
string texts[] = { "AUTUMN", "BONE", "JET" };
int size = sizeof(texts) / sizeof(string);
for (int i = 0; i < size; i++)
gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(colorize_combo), g_strdup_printf("%s", texts[i]));
but it doesn't work correctly.
UPDATED with how to decode the value in the combo box
You don't need g_strdup_printf: gtk_combo_box_text_append_text takes a const gchar *. This means it won't modify the string you pass, it will create a copy by itself.
At the top of your file, declare:
static const char *color_names[] = { "AUTUMN", "BONE", "JET" };
Then, where you're filling your combo box, replace:
string texts[] = { "AUTUMN", "BONE", "JET" };
int size = sizeof(texts) / sizeof(string);
for (int i = 0; i < size; i++)
gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(colorize_combo), g_strdup_printf("%s", texts[i]));
with:
for (int i = 0; i < G_N_ELEMENTS(texts); i++)
gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(colorize_combo), texts[i]);
Finally, where you read the text selected by the combo box, replace:
int type_color = atoi(gtk_combo_box_text_get_active_text(GTK_COMBO_BOX_TEXT(colorize_combo)));
with:
int type_color = -1;
gchar * selected_color_name = gtk_combo_box_text_get_active_text(GTK_COMBO_BOX_TEXT(colorize_combo));
for (int i = 0; i < G_N_ELEMENTS(color_names); i++)
if (g_strcmp0(selected_color_name, color_names[i]) == 0)
type_color = i;
// gtk_combo_box_text_get_active_text return a string that must be freed as stated in the doc
g_free(selected_color_name);

Confused About Passing Color to Class (Java)

Trying to write a program in which if a user enters in a name that is "Randy" than Java would generate a random number between 0 to 255 (RGB). If the name is "Prius" than the color would be green only. From there I would pass that random number or the green color into my tank class.
import java.awt.*;
import java.util.*;
public class Program4
{
public static void main(String[ ] args)
{
Scanner kb = new Scanner(System.in);
Random rand = new Random();
System.out.print("Please enter in your name: ");
String name = kb.nextLine();
if(name.equalsIgnoreCase ("Randy"))
{
for (int i=1 ; i<= 3; i++)
{
int color2 = rand.nextInt(255);
Color myColor = new Color (color2);
Tank myTank = new Tank(myColor, 25);
}
}
else if (name.equalsIgnoreCase ("Prius"))
{
Color myColor = new Color (0,255,0);
Tank myTank = new Tank(myColor,25);
}
//create a new instance of a Tank, get its dimension
Color myColor = new Color(255, 0, 255);
Tank myTank = new Tank(myColor, 25);
int dimension = myTank.getDimension();
//create a new instance of a Landscape
Landscape myLS = new Landscape();
//tell the landscape to add the tank to itself
myLS.addTank(myTank);
//tell the tank to turn around
myTank.turn("left");
myTank.turn("left");
//ask the landscape where is its green opening (as an int)
Point greenPoint = myLS.getGreenOpening();
int greenY = (int)greenPoint.getY();
//tell the tank to keep moving as long as it is above the green opening
while(myTank.getPositionY() + dimension < greenY)
myTank.move();
//turn left
myTank.turn("left");
//hopefully, move through the green wall
for (int i=0; i<200; i++)
myTank.move();
Point orangePoint = myLS.getOrangeOpening();
int orangeY = (int)orangePoint.getY();
if (myTank.getPositionY() + dimension < orangeY)
{
myTank.turn("right");
while (myTank.getPositionY() + dimension < orangeY)
{
myTank.move();
}
myTank.turn("left");
}
else
{
myTank.turn("left");
while (myTank.getPositionY() + dimension > orangeY)
{
myTank.move();
}
myTank.turn("right");
}
for (int i=0 ; i<200 ; i++)
myTank.move();
Point targetLocation = myLS.getTargetLocation();
int targetY = (int)targetLocation.getY();
if (myTank.getPositionY() + dimension <targetY)
{
myTank.turn("right");
while (myTank.getPositionY() + dimension < targetY + 30)
{
myTank.move();
}
myTank.turn("left");
}
else
{
myTank.turn("left");
while (myTank.getPositionY() + dimension > targetY + 30)
{
myTank.move();
}
myTank.turn("right");
}
for (int i=0 ; i<500 ; i++)
myTank.move();
}
}
There is more to the program however, I just need help with the colors. The program compiles and works. The only problem is the random color and green is not being passed onto my tank class. The default tank color is purple.
Thank you for the help.
Have you tried this?
Color myColor;
Tank myTank;
if(name.equalsIgnoreCase ("Randy"))
{
for (int i=1 ; i<= 3; i++)
{
int color2 = rand.nextInt(255);
myColor = new Color (color2);
myTank = new Tank(myColor, 25);
}
}
else if (name.equalsIgnoreCase ("Prius"))
{
myColor = new Color (0,255,0);
myTank = new Tank(myColor,25);
}
else
{
myColor = new Color(255, 0, 255);
myTank = new Tank(myColor, 25);
}
int dimension = myTank.getDimension();

(opencv) merge contours together

I am doing a real time motion detection program. I find that there are a lot of contour made in my different image after i used background subtraction method . i would like to ask is there any method that can merge these contour together or make a larger rect contain all the contours?
the case now i have been done
http://singhgaganpreet.files.wordpress.com/2012/07/motioncolour.jpg
My code is here
#include <iostream>
#include <OpenCV/cv.h>
#include <OPenCV/highgui.h>
using namespace cv;
using namespace std;
CvRect rect;
CvSeq* contours = 0;
CvMemStorage* storage = NULL;
CvCapture *cam;
IplImage *currentFrame, *currentFrame_grey, *differenceImg, *oldFrame_grey;
bool first = true;
int main(int argc, char* argv[])
{
//Create a new movie capture object.
cam = cvCaptureFromCAM(0);
//create storage for contours
storage = cvCreateMemStorage(0);
//capture current frame from webcam
currentFrame = cvQueryFrame(cam);
//Size of the image.
CvSize imgSize;
imgSize.width = currentFrame->width;
imgSize.height = currentFrame->height;
//Images to use in the program.
currentFrame_grey = cvCreateImage( imgSize, IPL_DEPTH_8U, 1);
while(1)
{
currentFrame = cvQueryFrame( cam );
if( !currentFrame ) break;
//Convert the image to grayscale.
cvCvtColor(currentFrame,currentFrame_grey,CV_RGB2GRAY);
if(first) //Capturing Background for the first time
{
differenceImg = cvCloneImage(currentFrame_grey);
oldFrame_grey = cvCloneImage(currentFrame_grey);
cvConvertScale(currentFrame_grey, oldFrame_grey, 1.0, 0.0);
first = false;
continue;
}
//Minus the current frame from the moving average.
cvAbsDiff(oldFrame_grey,currentFrame_grey,differenceImg);
//bluring the differnece image
cvSmooth(differenceImg, differenceImg, CV_BLUR);
//apply threshold to discard small unwanted movements
cvThreshold(differenceImg, differenceImg, 25, 255, CV_THRESH_BINARY);
//find contours
cvFindContours( differenceImg, storage, &contours );
//draw bounding box around each contour
for(; contours!=0; contours = contours->h_next)
{
rect = cvBoundingRect(contours, 0); //extract bounding box for current contour
//drawing rectangle
cvRectangle(currentFrame,
cvPoint(rect.x, rect.y),
cvPoint(rect.x+rect.width, rect.y+rect.height),
cvScalar(0, 0, 255, 0),
2, 8, 0);
}
//display colour image with bounding box
cvShowImage("Output Image", currentFrame);
//display threshold image
cvShowImage("Difference image", differenceImg);
//New Background
cvConvertScale(currentFrame_grey, oldFrame_grey, 1.0, 0.0);
//clear memory and contours
cvClearMemStorage( storage );
contours = 0;
//press Esc to exit
char c = cvWaitKey(33);
if( c == 27 ) break;
}
// Destroy the image & movies objects
cvReleaseImage(&oldFrame_grey);
cvReleaseImage(&differenceImg);
cvReleaseImage(&currentFrame);
cvReleaseImage(&currentFrame_grey);
//cvReleaseCapture(&cam);
return 0;
}
Did you try this?
std::vector<cv::Point> points;
points.insert(points.end(), contour1.begin(), contour1.end());
points.insert(points.end(), contour2.begin(), contour2.end());
convexHull(cv::Mat(points), contour);
PS. For some applications, it may be better to use approxPoly() rather than convexHull(). Just try both.
PPS. Try smoothing the resulting contour with gaussian. It also can be helpful.
I came across a similar problem. In my case I created an empty sequence then I filled it with the points of each contour, after that I fitted a bounding ellipse with that sequence.
Here is my code segment...
CvMemStorage *storage = cvCreateMemStorage ();
CvMemStorage *storage1 = cvCreateMemStorage ();
CvSeq *contours = 0;
//find contour in BInv
cvFindContours (BInv, storage, &contours, sizeof(CvContour), CV_RETR_LIST,CV_CHAIN_APPROX_NONE ,cvPoint(0,0));
//creating empty sequence of CvPoint
CvSeq* seq = cvCreateSeq(CV_SEQ_ELTYPE_POINT/*| CV_SEQ_KIND_SET | CV_SEQ_FLAG_SIMPLE*/,sizeof(CvSeq),sizeof(CvPoint),storage1);
//populating seq with all contours
for(; contours!=0; contours = contours->h_next)
for(int i=0;i<contours->total;i++)
{
CvPoint* p;
p = (CvPoint*)cvGetSeqElem (contours, i );
cvSeqPush(seq,p);
}
//bounding box and drawing
CvBox2D bbox=cvMinAreaRect2(seq, NULL );
cvEllipseBox(color,bbox,cvScalarAll(0),5,8,0);
hope this helps.
If you want to merge contours on the basis of distance apart then you can do something like this:
struct hash_pair {
template <class T1, class T2>
size_t operator()(const pair<T1, T2>& p) const
{
auto hash1 = hash<T1>{}(p.first);
auto hash2 = hash<T2>{}(p.second);
if (hash1 != hash2) {
return hash1 ^ hash2;
}
return hash1;
}
};
void findPixelsNearby(unordered_map<pair<int, int>,bool,hash_pair>&res, Point px,int pxlVal) {
for (int itr1 = (px.x) - pxlVal; itr1 <= (px.x) + pxlVal; itr1++) {
for (int itr2 = (px.y - pxlVal); itr2 <= (px.y) + pxlVal; itr2++) {
res[{itr1, itr2}] = true;
}
}
}
unordered_map<pair<int, int>, bool, hash_pair> createSets(vector<Point2f>Contour, int rect) {
unordered_map<pair<int,int>,bool,hash_pair>res;
for (auto tra : Contour) {
Point px = (Point)tra;
findPixelsNearby(res,px,rect);
}
return res;
}
//void drawContour(Mat& img, vector<Point2f>s1,int px,int py,int pz) {
// for (auto x : s1) {
// line(img, x, x, Scalar(px, py, pz), 4, 0);
//
// }
// resShow("temp",img,1);
//}
bool hasCommon(unordered_map<pair<int,int>,bool,hash_pair>s1, unordered_map<pair<int, int>, bool, hash_pair>s2){
for (auto x : s1) {
if (s2.find(x.first) != s2.end()) {
return true;
}
}
return false;
}
void MergeContours(Mat image, vector<Contour>&usableContours,int distance_considered, vector<Contour>& finalContours) {
int numberContours = usableContours.size();
vector<vector<int>>ids_for_contour_merge(numberContours);
vector<unordered_map<pair<int, int>, bool, hash_pair>>ContourSets;
vector<bool>boolVals(numberContours,false);
for (int i = 0; i < numberContours; i++) {
ContourSets.push_back(createSets(usableContours[i].points, distance_considered/2));
}
for (int i = 0; i < numberContours; i++) {
if (boolVals[i] == false) {
boolVals[i] = true;
for (int j = i+1; j < numberContours; j++) {
if (boolVals[j] == false) {
if(hasCommon(ContourSets[i], ContourSets[j])==true){
ContourSets[i].insert(ContourSets[j].begin(), ContourSets[j].end());
boolVals[j] = true;
ids_for_contour_merge[i].push_back(j);
j = i;
}
}
}
}
}
vector<bool>Visited(ids_for_contour_merge.size(), false);
for (int mr = 0; mr < ids_for_contour_merge.size(); mr++) {
if (Visited[mr] == false) {
vector<Point2f>temp=usableContours[mr].points;
if (ids_for_contour_merge[mr].size() > 0) {
for (int mc = 0; mc < ids_for_contour_merge[mr].size(); mc++) {
int valPtr = ids_for_contour_merge[mr][mc];
copy(usableContours[valPtr].points.begin(), usableContours[valPtr].points.end(), std::back_inserter(temp));
Visited[valPtr] = true;
}
}
else {
Visited[mr] = true;
}
Contour newCtr;
newCtr.points = temp;
finalContours.push_back(newCtr);
}
}
///////////////////////////////////////////////////////////////DRAWING CONTOURS
/*for (auto x : finalContours) {
cout <<"CONTOURS FINAL SIZE IS : " <<x.points.size()<<endl;
int px = 0;
int py = 0;
int pz = 0;
drawContour(image, x.points, ((px+rand())%255), ((py + rand()) % 255), ((pz + rand()) % 255));
}*/
//////////////////////////////////////////////////////////////////////////////
}
More On Github: https://github.com/HimanshuYadav117/Merge-Contours/blob/main/MergeContours.cpp