int arrow_detection::featureExteraction(Mat arrow,vector<float> &features){
    features.clear();
    Mat binary;
    vector <std::vector<cv::Point2i >> blobs;
    vector<Rect> blobs_roi;

    preProcessing(arrow, binary);
    // viewImage(binary*255,"binary arrow");
    segmentation(binary,blobs_roi, blobs);
    // DEBUG_LOG("Blobs attained : %ld\n",blobs_roi.size());
    if(blobs_roi.size() > 1){
        // ERROR_LOG("More than one blobs detected possibly an error.");
        return -1;
    }
    float convex_area = blobs[0].size();
    features.push_back(convex_area);
    // DEBUG_LOG("convex_area : %f\n",convex_area);

    Rect arrow_rect(blobs_roi[0]);
    float a = 0,b = 0;
    if(arrow_rect.width > arrow_rect.height){
        a = arrow_rect.width/2;
        b = arrow_rect.height/2;
    }else{
        a = arrow_rect.height/2;
        b = arrow_rect.width/2;
    }
    
    // DEBUG_LOG("semi major axis: %f\n",a);
    // DEBUG_LOG("semi minor axis: %f\n",b);
    // DEBUG_LOG("their ratio: %f\n",b/a);
    // DEBUG_LOG("pow(b/a,2) : %f\n",pow(b/a,2));
    float ecentricity = sqrtf(1-pow(b/a,2));
    features.push_back(ecentricity);
    // DEBUG_LOG("ecentricity : %f\n",ecentricity);

    float extent = convex_area/float(arrow.total());
    features.push_back(extent);
    // DEBUG_LOG("extent : %f\n",extent);

    float solidity = float(arrow.total())/convex_area;
    features.push_back(extent);
    // DEBUG_LOG("solidity : %f\n",solidity);

    return 0;
}
void PopupMenuWindow::on_render(Canvas &canvas, const Rect &update_rect)
{
	Rect rect = get_geometry().get_size();

	if (menu.impl->joiner_width > 0)
	{
	    Rect joiner_rect(0, 0, menu.impl->joiner_width, part_menubar_joiner.get_css_height());
		part_menubar_joiner.render_box(canvas, joiner_rect);
	}

	Rect client_box = get_content_box();

	int offset = 0;

	int count = menu.get_item_count();
	for (int index = 0; index < count; index++)
	{
		PopupMenuItem item = menu.get_item_at(index);
		bool is_selected = (index == selected);
		int row_height = 0;

		if (item.is_separator())
		{
			row_height = part_separator.get_css_height();
			Rect separator_render_rect(client_box.left, offset, client_box.right, offset+row_height);
			Rect separator_content_rect = part_separator.get_content_box(separator_render_rect);
			separator_content_rect.right -= 4; // This thing is already a hack (render to content to render content as render, wtf? :))
			separator_content_rect.top += 3; // More hacks..
			separator_content_rect.bottom += 3; // Something is really wrong about this stuff. But it fixes the visual layout.
			part_separator.render_box(canvas, separator_content_rect);
		}
		else
		{
			part_item_row.set_pseudo_class(CssStr::selected, is_selected);
			part_item_icon.set_pseudo_class(CssStr::selected, is_selected);
			part_item_label.set_pseudo_class(CssStr::selected, is_selected);

			part_item_row.set_pseudo_class(CssStr::disabled, item.is_disabled());
			part_item_icon.set_pseudo_class(CssStr::disabled, item.is_disabled());
			part_item_check.set_pseudo_class(CssStr::disabled, item.is_disabled());
			part_item_label.set_pseudo_class(CssStr::disabled, item.is_disabled());
			part_item_accel_label.set_pseudo_class(CssStr::disabled, item.is_disabled());

			row_height = part_item_row.get_css_height();

			// row rect
			Rect row_rect(Point(client_box.left, client_box.top + offset), Size(client_box.right, row_height));
			part_item_row.render_box(canvas, row_rect);
			Rect row_box = part_item_row.get_content_box(row_rect);

			// icon or check
			if (item.is_checkable())
			{
				if (item.is_checked())
				{
					Rect rect(Point(row_box.left, (row_box.top + row_box.bottom)/2 - check_size.height/2), check_size);
					part_item_check.render_box(canvas, rect);
				}
			}
			else
			{
				PixelBuffer pbuf_icon = item.get_icon();
				if (!pbuf_icon.is_null())
				{
					Size icon_size = pbuf_icon.get_size();
					Rect rect(Point(row_box.left, (row_box.top + row_box.bottom)/2 - icon_size.height/2), icon_size);

					Image image(canvas, pbuf_icon, pbuf_icon.get_size());	//TODO: This is slow, and probably should be cached
					image.set_linear_filter(false);
						Colorf color = Colorf::white;
					if (item.is_disabled())
					image.set_alpha(0.25f);
					image.draw(canvas, rect);
				}
			}

			// item text
			Size text_size = part_item_label.get_render_text_size(canvas, item.get_text());
			Size text_full_size = part_item_label.get_border_box(text_size).get_size();

			Rect label_render_rect(row_box.left + icon_column_width, row_box.top, row_box.left + icon_column_width + text_full_size.width, row_box.bottom);
			Rect label_content_rect = part_item_label.get_content_box(label_render_rect);

			part_item_label.render_box(canvas, label_render_rect);
			part_item_label.render_text(canvas, item.get_text(), label_content_rect);

			int center_y = row_box.get_center().y;
			int arrow_width = part_submenu_arrow.get_css_width();
			int arrow_height = part_submenu_arrow.get_css_height();

			if (item.has_submenu())
			{
				Rect arrow_rect(
					row_box.right - arrow_width,
					center_y - arrow_height/2,
					row_box.right,
					center_y + arrow_height/2);

				Rect arrow_content = part_submenu_arrow.get_content_box(arrow_rect);

				part_submenu_arrow.render_box(canvas, arrow_content);
			}
			else if (!item.get_accelerator_text().empty())
			{
				// accelerator text
				Size accel_text_size = part_item_accel_label.get_render_text_size(canvas, item.get_accelerator_text());
				Size accel_text_full_size = part_item_accel_label.get_border_box(accel_text_size).get_size();

				Rect accel_render_rect(
					row_box.right-arrow_width-accel_text_full_size.width, 
					label_content_rect.top, 
					row_box.right-arrow_width, 
					label_content_rect.bottom);

				Rect accel_content_rect = part_item_accel_label.get_content_box(accel_render_rect);

				part_item_accel_label.render_text( canvas, item.get_accelerator_text(), accel_content_rect);
			}
		}

		offset += row_height;
	}
}