예제 #1
0
//
// Generate the segmented image and send to a given port.
//	- it gets image from processed sequence.
int 
YARPFlowTracker::GenerateAndSend(YARPOutputPortOf<YARPGenericImage>& port)
{
	// segmentation_mask_copy
	// frame from seq
	// port from reader

	// YARPImageSequence& seq = reader->GetSequenceRef();
	// YARPOutputPortOf<YARPGenericImage>& port = reader->GetSegmentedImagePort();

	YARPImageOf<YarpPixelBGR>& frame = seq->GetImageRef (contact_frame);
	YARPImageOf<YarpPixelMono>& mask = segmentation_mask_copy;

#ifdef LOGGING_SEGMENTATIONS
	// awful to just hack this in here... bound to cause trouble...
	// but I'm going to do it anyway.
#ifdef SENDING_SEGMENTATIONS
	{
	  // send frame and mask
	  out_seg.Content().c1.PeerCopy(frame);
	  out_seg.Content().c2.PeerCopy(frame);
	  out_seg.Content().c2.CastCopy(mask);
	  out_seg.Write();
	}
#endif	  
	{
	  char buf[256];
	  long int tick = (long int) YARPTime::GetTimeAsSeconds();
	  sprintf(buf,"%s/%ld.ppm", LOGGING_DIR, tick);
	  printf("Saving frame %s\n", buf);
	  YARPImageFile::Write(buf,frame);
	  sprintf(buf,"%s/%ld.pgm", LOGGING_DIR, tick);
	  printf("Saving mask %s\n", buf);
	  YARPImageFile::Write(buf,mask);
	}
#endif

	YarpPixelBGR black;
	black.r = black.g = black.b = 0;
	YarpPixelBGR black1;
	black1.r = black1.g = black1.b = 1;

	for (int i = 0; i < mask.GetHeight(); i++)
		for (int j = 0; j < mask.GetWidth(); j++)
		{
			if (frame(j,i).r != 0 ||
				frame(j,i).g != 0 ||
				frame(j,i).b != 0)
				output_image(j,i) = (mask(j,i) != 0) ? frame(j,i) : black;
			else
				output_image(j,i) = (mask(j,i) != 0) ? frame(j,i) : black1;
		}

	// send.
	port.Content().Refer (output_image); 
	port.Write ();

	return 0;
}
예제 #2
0
void RaytracerApplication::handle_event( const SDL_Event& event )
{
    int width, height;

    if ( !raytracing ) {
        camera_control.handle_event( this, event );
    }

    switch ( event.type )
    {
    case SDL_KEYDOWN:
        switch ( event.key.keysym.sym )
        {
        case KEY_RAYTRACE:
            get_dimension( &width, &height );
            toggle_raytracing( width, height );
            break;
        case KEY_SCREENSHOT:
            output_image();
            break;
        default:
            break;
        }
    default:
        break;
    }
}
예제 #3
0
void RaytracerApplication::handle_event( const SDL_Event& event )
{
    int width, height;

    if ( !raytracing ) {
        camera_control.handle_event( this, event );
    }

    switch ( event.type )
    {
    case SDL_KEYDOWN:
        switch ( event.key.keysym.sym )
        {
        case KEY_RAYTRACE:
            get_dimension( &width, &height );
            toggle_raytracing( width, height );
            break;
        case KEY_SEND_PHOTONS:
            raytracer.initialize(&scene, options.num_samples, 0, 0);
            queue_render_photon=true;
            
        case KEY_SCREENSHOT:
            output_image();
            break;
        default:
            break;
        }
    default:
        break;
    }
}
예제 #4
0
int
main( int	argc,
     char *	argv[] )
{
  ProgName = argv[0];
       
  switch (setup ( argc, argv ))
    {
    default:
    case SYSBUILD_FAIL: break;
    case SYSBUILD_OK:
      parse_config_file (ConfigData.config_file);
  
      update_configdata ();
  
      print_configdata ();
  
      if (!ShowOnly)
	{
	  make_nucleus ();
  
	  check_bootstrap ();
  
	  output_image ();
	}
      
      break;
      
    case SYSBUILD_OLD:
      sysbuild( argc, argv );
      break;
    }
    
  tidyup ();
}
예제 #5
0
 void rose_of_directions::draw_rod(const std::vector<float>& rose_vec) const {
   std::cerr << "      --> compute_from_..._in(...)" << std::endl;
   std::srand(time(NULL));
   std::stringstream ss;
   ss << "rod_" << std::size_t(rand()) << ".png";
   std::string output_fname = ss.str();
   std::size_t rose_vec_size = rose_vec.size();
   float rod_min = 1e30f;
   float rod_max = 0.0f;
   for (std::size_t j = 0; j < rose_vec_size; ++j) {
     rod_min = std::min(rod_min,rose_vec[j]);
     rod_max = std::max(rod_max,rose_vec[j]);
   }
   int width  = int(rose_vec_size);
   int height = int(rose_vec_size*3/4);
   image_t output_image(height,width,CV_8UC3);
   output_image.setTo(cv::Vec3b(0,0,0));
   for (std::size_t j = 0; j < rose_vec_size; ++j) {
     float value = float(height-1) * (rose_vec[j] - rod_min) / (rod_max - rod_min);
     cv::Point p0, p1;
     p0.x = j;
     p1.x = j;
     p0.y = height;
     p1.y = height - int(value);
     cv::line(output_image,p0,p1,cv::Scalar(0,255,0),1);
   }
   cv::imwrite(output_fname.c_str(),output_image);
   std::cerr << "          - writing rod image - " << output_fname << std::endl;
 }
예제 #6
0
int main(int argc, char* argv[])
{
    process_options(argc, argv);
    create_image_preprocess();
    create_image();
    output_image();
    return 0;
}
예제 #7
0
bool write_argb_image(const cv::Mat& argb_image, const std::string& output_filename)
{
    cv::Mat output_image(argb_image.size(), CV_8UC3);
    int argb_to_bgr[] = { 3,0, // blue
            2,1, // green
            1,2 // red
    };
    cv::mixChannels(&argb_image, 1, &output_image, 1, argb_to_bgr, 3);
    return write_bgr_image(output_image, output_filename);
}
예제 #8
0
void DrawWindow::on_pushButton_exportDiagram_clicked()
{
	QString output_filename = QFileDialog::getSaveFileName(	this,
															"Choose location...",
															"Auton Diagram.png",
															"PNG images (*.png)");
	QSize output_size = field.itemsBoundingRect().size().toSize()*8;
	QImage output_image(output_size, QImage::Format_ARGB32);
	output_image.fill(Qt::transparent);
	QPainter output_painter(&output_image);
	output_painter.setRenderHint(QPainter::Antialiasing);
	ui->graphicsView->render(	&output_painter,
								QRect(),
								QRect(ui->graphicsView->mapFromScene(-10, -10), ui->graphicsView->mapFromScene(154, 154)),
								Qt::KeepAspectRatio);
	output_image.save(output_filename, "png", 0);
}
예제 #9
0
파일: main.c 프로젝트: SySof/sysof
int main(int argc, char** argv){
    int c;
    long double x = 2.1;
    long double y = 2.3;
    long double d = 5;
    int w = 800;
    int h = 600;
    int i = 200;
    while((c = getopt(argc, argv, "x:y:w:h:d:i:")) != -1) {
        switch(c) {
            case 'x':
                x = atof(optarg);
                break;
            case 'y':
                y = atof(optarg);
                break;
            case 'd':
                d = atof(optarg);
                break;
            case 'w':
                w = atoi(optarg);
                break;
            case 'h':
                h = atoi(optarg);
                break;
            case 'i':
                i = atoi(optarg);
                break;
            case ':':
                switch(optopt) {
                    case '?':
                        printf(usage);
                        return  1;
                    default:
                        break;
                }
                break;
            default:
                printf(usage);
                return 1;
        }
    }
    output_image(x, y, d, w, h, i);
}
예제 #10
0
void export_bitmap(const char *fname, const Buffer *buffer, int channels)
{
    int width_i = static_cast<int>(buffer->buffer_width_f);
    int height_i = static_cast<int>(buffer->buffer_height_f);

    shared_ptr<uint8_t> processed_buffer(new uint8_t[4 * width_i * height_i]);
    uint8_t default_channel_vals[] = {0, 0, 0, 255};

    uint8_t* out_ptr = processed_buffer.get();
    const T* in_ptr = reinterpret_cast<T*>(buffer->buffer);

    const float *bc_comp = buffer->auto_buffer_contrast_brightness();
    float color_scale = get_multiplier<T>();

    const float maxIntensity = get_max_intensity<T>();

    for(int y = height_i - 1; y >= 0; --y) {
        for(int x = width_i - 1; x >= 0; --x) {
            int c;
            for(c = 0; c < channels; ++c)  {
                float in_val = static_cast<float>(in_ptr[y * channels * width_i + x * channels + c]);
                out_ptr[y * 4 * width_i + x * 4 + c] = static_cast<uint8_t>(
                            clamp((in_val * bc_comp[c] + bc_comp[4 + c]*maxIntensity)*color_scale, 0.f, 255.f));
            }
            if(channels == 1) {
                // Grayscale: Repeat first channel into G and B
                for(; c < 3; ++c) {
                  out_ptr[y * 4 * width_i + x * 4 + c] = out_ptr[y * 4 * width_i + x * 4];
                }
                out_ptr[y * 4 * width_i + x * 4 + c] = 255;
            } else {
                for(; c < 4; ++c) {
                  out_ptr[y * 4 * width_i + x * 4 + c] = default_channel_vals[c];
                }
            }
        }
    }

    const int bytes_per_line = width_i * 4;
    QImage output_image(processed_buffer.get(), width_i, height_i, bytes_per_line, QImage::Format_RGBA8888);
    output_image.save(fname, "png");
}
예제 #11
0
파일: hw1.cpp 프로젝트: yuanb10/csci1200
int main(int argc, char* argv[]) {
    // check if the argument number is valid
    if (argc < 4) {
        std::cerr << "Usage: "
                  << argv[0]
                  << " input-file output-file [operations] [parameters]"
                  << std::endl;
        return 1;
    }
    // check if the input file is valid
    std::ifstream input(argv[1]);
    if (!input) {
        std::cerr << "Can not open the grades in file " << argv[1] << std::endl;
        return 1;
    }
    // read in the image
    std::vector<std::string> image;
    read_in_image(input, image);

    if (image.size() == 0) {
        std::cout << "Cannot import the image "
                  << argv[1]
                  << ". Try again please. "
                  << std::endl;
        return 1;
    }

    std::ofstream output(argv[2]);   // the output file
    std::string op = argv[3];   // the operation name

    if (op.compare("replace") == 0 && argc == 6) {  // replace
        char before  = argv[4][0];
        char after  = argv[5][0];
        replace(image, before, after);
    } else if (op.compare("dilation") == 0 &&
               (argc == 5 || argc == 6)) {   // dilation operation
        char color = argv[4][0];
        if (argc == 5) {
            // When plus-signed structing element
            dilation(image, color, false);
        } else if (argc == 6 && std::string(argv[5]).compare("square") == 0) {
            // when square-signed structing element
            dilation(image, color, true);
        } else {
            std::cerr << "Usage: "
                      << argv[0]
                      << " input-file output-file dilation color [square]"
                      << std::endl;
            return 1;
        }
    } else if (op.compare("erosion") == 0 &&
               (argc == 6 || argc == 7)) {   // erosion operation
        char color = argv[4][0];
        char pixel = argv[5][0];
        if (argc == 6) {
            // When plus-signed structing element
            erosion(image, color, pixel, false);
        } else if (argc == 7 && std::string(argv[6]).compare("square") == 0) {
            // when square-signed structing element
            erosion(image, color, pixel, true);
        } else {
            std::cerr << "Usage: " << argv[0]
                      << " input-file output-file erosion pixel [square]"
                      << std::endl;
            return 1;
        }
    } else if (op.compare("floodfill") == 0 && argc == 7) {
        // floodfill operation
        int row = atoi(argv[4]);
        int col = atoi(argv[5]);
        if (!isValid(image, row, col)) {
            std::cerr << "Error: invalid arguments "
                      << row << " and " << col
                      << std::endl;
            return 1;
        }
        char filler = argv[6][0];
        flood_fill(image, row, col, filler);
    } else {   // invalid input command
        std::cerr << "Invalid command." << std::endl;
        std::cerr << "Usage: " << argv[0]
                  << " input-file output-file [operations] [parameters]"
                  << std::endl;
        return 1;
    }

    // write the modified image to a file
    if (output.is_open()) {
        output_image(image, output);
        output.close();
    } else {
        std::cerr << "Cannot output to " << argv[3] << std::endl;
        return 1;
    }
    return 0;
}
예제 #12
0
int main(int argc,char** argv)
	{
	int width;
	int height;
	
	const char* source;		// Source code
	cl_platform_id platform;	// Platform { CPU, GPU, FPGA }
	cl_device_id device;		// Device { GPU_ID }
	cl_context context;		// Context
	cl_command_queue queue;		// Queue 
	cl_int err;			// for error checking

	cl_event event[NR_KERNELS-1];	// must be ok for second kernel to run

	cl_program program;		// program
	cl_kernel kernels_code[NR_KERNELS];


	cl_mem bufferIN;	// data IN
	cl_mem bufferOUT;	// data OUT

	int* inputImage;	// input image
	int* outputImage;	// output image

	cl_uint *ptr;			// data to be shown
	size_t global_work_size;	// work size

	// get platform, get device, create context
	clGetPlatformIDs(1,&platform,NULL);
	clGetDeviceIDs(platform,COMPUTE,1,&device,NULL);
	context=clCreateContext(NULL,1,&device,NULL,NULL,NULL);
	queue=clCreateCommandQueue(context,device,0,NULL);

	
	
	// read data from file, allocate memory & copy
	inputImage=input_image(INPUT_IMAGE,&width,&height);
	
	bufferIN=clCreateBuffer(context,CL_MEM_READ_WRITE,width*height *sizeof(int),NULL,NULL);
	clEnqueueWriteBuffer(queue,bufferIN,1,0,width * height * sizeof(int),inputImage,0,0,0);

	bufferOUT= clCreateBuffer(context,CL_MEM_READ_WRITE,width*height *sizeof(int),NULL,NULL);	

	// read code from file / check code
	source=readCode(FILENAME);
	if(source==NULL)
		{
		printf("Error reading code. Exiting");
		return 1;
		}
	
	// init OPENCL program
	
	
	program=clCreateProgramWithSource(context,1,&source,NULL,&err);
	check(err,program,device);
	check(clBuildProgram(program,1,&device,NULL,NULL,NULL));


	// kernels
	for(int i=0;i<NR_KERNELS;i++)
		{
			kernels_code[i]=clCreateKernel(program,kernels[i],&err);
			check(err,program,device);
		}
	

	// pass args, execute OPENCL kernels
	global_work_size=width*height;

	for(int i=0;i<NR_KERNELS;i++)
	{	
		if((i+1)%2==0){
			check(clSetKernelArg(kernels_code[i],0,sizeof(bufferOUT),(void*)&bufferOUT));
			check(clSetKernelArg(kernels_code[i],1,sizeof(bufferIN),(void*)&bufferIN));
			check(clSetKernelArg(kernels_code[i],2,sizeof(int),(void*)&width));
			check(clSetKernelArg(kernels_code[i],3,sizeof(int),(void*)&height));
			}
		else {
			check(clSetKernelArg(kernels_code[i],0,sizeof(bufferIN),(void*)&bufferIN));
			check(clSetKernelArg(kernels_code[i],1,sizeof(bufferOUT),(void*)&bufferOUT));
			check(clSetKernelArg(kernels_code[i],2,sizeof(int),(void*)&width));
			check(clSetKernelArg(kernels_code[i],3,sizeof(int),(void*)&height));
			}
	}

	

	
	size_t global_work[2];
	global_work[0]=width;
	global_work[1]=height;

	// enqueue / run all kernels (pipeline in this case)

	// start first kernel
	check(clEnqueueNDRangeKernel(queue,kernels_code[0],2,NULL,global_work,NULL,0,NULL,&event[0]));

	// run all the rest (n-2)
	for(int i=1;i<NR_KERNELS-1;i++)
		check(clEnqueueNDRangeKernel(queue,kernels_code[i],2,NULL,global_work,NULL,i,event,&event[i]));

	// start last kernel
	if(NR_KERNELS>2)
	check(clEnqueueNDRangeKernel(queue,kernels_code[NR_KERNELS-1],2,NULL,global_work,NULL,NR_KERNELS-1,event,NULL));
		
	
	// finish queue
	check(clFinish(queue));
	 
	if(NR_KERNELS%2==1)
    		outputImage= (int*)clEnqueueMapBuffer(queue,bufferOUT,CL_TRUE,CL_MAP_READ,0,width*height*sizeof(int),0,NULL,NULL,NULL);
	else 
		outputImage= (int*)clEnqueueMapBuffer(queue,bufferIN,CL_TRUE,CL_MAP_READ,0,width*height*sizeof(int),0,NULL,NULL,NULL);
    	
    	output_image(OUTPUT_IMAGE,outputImage,width,height);
	return 0;
}
예제 #13
0
  // Processes the point cloud with OpenCV using the PCL cluster indices
  void processClusters( const std::vector<pcl::PointIndices> cluster_indices,
                        //                        const sensor_msgs::PointCloud2ConstPtr& pointcloud_msg,
                        const pcl::PointCloud<pcl::PointXYZRGB>::ConstPtr  cloud_transformed,
                        const pcl::PointCloud<pcl::PointXYZRGB>::ConstPtr& cloud_filtered,
                        const pcl::PointCloud<pcl::PointXYZRGB>&  cloud )
  {

    // -------------------------------------------------------------------------------------------------------
    // Convert image
    ROS_INFO_STREAM_NAMED("perception","Converting image to OpenCV format");

    try
    {
      sensor_msgs::ImagePtr image_msg(new sensor_msgs::Image);
      //      pcl::toROSMsg (*pointcloud_msg, *image_msg);
      pcl::toROSMsg (*cloud_transformed, *image_msg);
      cv_bridge::CvImagePtr input_bridge = cv_bridge::toCvCopy(image_msg, "rgb8");
      full_input_image = input_bridge->image;
    }
    catch (cv_bridge::Exception& ex)
    {
      ROS_ERROR_STREAM_NAMED("perception","[calibrate] Failed to convert image");
      return;
    }

    // -------------------------------------------------------------------------------------------------------
    // Process Image

    // Convert image to gray
    cv::cvtColor( full_input_image, full_input_image_gray, CV_BGR2GRAY );
    //cv::adaptiveThreshold( full_input_image, full_input_image_gray, 255, CV_ADAPTIVE_THRESH_MEAN_C, CV_THRESH_BINARY,5,10);

    // Blur image - reduce noise with a 3x3 kernel
    cv::blur( full_input_image_gray, full_input_image_gray, cv::Size(3,3) );

    ROS_INFO_STREAM_NAMED("perception","Finished coverting");

    // -------------------------------------------------------------------------------------------------------
    // Check OpenCV and PCL image height for errors
    int image_width = cloud.width;
    int image_height = cloud.height;
    ROS_DEBUG_STREAM( "PCL Image height " << image_height << " -- width " << image_width << "\n");
    int image_width_cv = full_input_image.size.p[1];
    int image_height_cv = full_input_image.size.p[0];
    ROS_DEBUG_STREAM( "OpenCV Image height " << image_height_cv << " -- width " << image_width_cv << "\n");

    if( image_width != image_width_cv || image_height != image_height_cv )
    {
      ROS_ERROR_STREAM_NAMED("perception","PCL and OpenCV image heights/widths do not match!");
      return;
    }

    // -------------------------------------------------------------------------------------------------------
    // GUI Stuff

    // First window
    const char* opencv_window = "Source";
    /*
      cv::namedWindow( opencv_window, CV_WINDOW_AUTOSIZE );
      cv::imshow( opencv_window, full_input_image_gray );
    */


    //    while(true)  // use this when we want to tweak the image
    {

      output_image = full_input_image.clone();

      // -------------------------------------------------------------------------------------------------------
      // Start processing clusters
      ROS_INFO_STREAM_NAMED("perception","Finding min/max in x/y axis");

      int top_image_overlay_x = 0; // tracks were to copyTo the mini images

      // for each cluster, see if it is a block
      for(size_t c = 0; c < cluster_indices.size(); ++c)
      {
        ROS_INFO_STREAM_NAMED("perception","\n\n");
        ROS_INFO_STREAM_NAMED("perception","On cluster " << c);

        // find the outer dimensions of the cluster
        double xmin = 0; double xmax = 0;
        double ymin = 0; double ymax = 0;

        // also remember each min & max's correponding other coordinate (not needed for z)
        double xminy = 0; double xmaxy = 0;
        double yminx = 0; double ymaxx = 0;

        // also remember their corresponding indice
        int xmini = 0; int xmaxi = 0;
        int ymini = 0; int ymaxi = 0;

        // loop through and find all min/max of x/y
        for(size_t i = 0; i < cluster_indices[c].indices.size(); i++)
        {
          int j = cluster_indices[c].indices[i];

          // Get RGB from point cloud
          pcl::PointXYZRGB p = cloud_transformed->points[j];

          double x = p.x;
          double y = p.y;

          if(i == 0) // initial values
          {
            xmin = xmax = x;
            ymin = ymax = y;
            xminy = xmaxy = y;
            yminx = ymaxx = x;
            xmini = xmaxi = ymini = ymaxi = j; // record the indice corresponding to the min/max
          }
          else
          {
            if( x < xmin )
            {
              xmin = x;
              xminy = y;
              xmini = j;
            }
            if( x > xmax )
            {
              xmax = x;
              xmaxy = y;
              xmaxi = j;
            }
            if( y < ymin )
            {
              ymin = y;
              yminx = x;
              ymini = j;
            }
            if( y > ymax )
            {
              ymax = y;
              ymaxx = x;
              ymaxi = j;
            }
          }
        }

        ROS_DEBUG_STREAM_NAMED("perception","Cluster size - xmin: " << xmin << " xmax: " << xmax << " ymin: " << ymin << " ymax: " << ymax);
        ROS_DEBUG_STREAM_NAMED("perception","Cluster size - xmini: " << xmini << " xmaxi: " << xmaxi << " ymini: " << ymini << " ymaxi: " << ymaxi);

        // ---------------------------------------------------------------------------------------------
        // Check if these dimensions make sense for the block size specified
        double xside = xmax-xmin;
        double yside = ymax-ymin;

        const double tol = 0.01; // 1 cm error tolerance

        // In order to be part of the block, xside and yside must be between
        // blocksize and blocksize*sqrt(2)
        if(xside > block_size-tol &&
           xside < block_size*sqrt(2)+tol &&
                   yside > block_size-tol &&
          yside < block_size*sqrt(2)+tol )
        {

          // -------------------------------------------------------------------------------------------------------
          // Get the four farthest corners of the block - use OpenCV only on the region identified by PCL

          // Get the pixel coordinates of the xmax and ymax indicies
          int px_xmax = 0; int py_xmax = 0;
          int px_ymax = 0; int py_ymax = 0;
          getXYCoordinates( xmaxi, image_height, image_width, px_xmax, py_xmax);
          getXYCoordinates( ymaxi, image_height, image_width, px_ymax, py_ymax);

          // Get the pixel coordinates of the xmin and ymin indicies
          int px_xmin = 0; int py_xmin = 0;
          int px_ymin = 0; int py_ymin = 0;
          getXYCoordinates( xmini, image_height, image_width, px_xmin, py_xmin);
          getXYCoordinates( ymini, image_height, image_width, px_ymin, py_ymin);

          ROS_DEBUG_STREAM_NAMED("perception","px_xmin " << px_xmin << " px_xmax: " << px_xmax << " py_ymin: " << py_ymin << " py_ymax: " << py_ymax );

          // -------------------------------------------------------------------------------------------------------
          // Change the frame of reference from the robot to the camera

          // Create an array of all the x value options
          const int x_values_a[] = {px_xmax, px_ymax, px_xmin, px_ymin};
          const int y_values_a[] = {py_xmax, py_ymax, py_xmin, py_ymin};
          // Turn it into a vector
          std::vector<int> x_values (x_values_a, x_values_a + sizeof(x_values_a) / sizeof(x_values_a[0]));
          std::vector<int> y_values (y_values_a, y_values_a + sizeof(y_values_a) / sizeof(y_values_a[0]));
          // Find the min
          int x1 = *std::min_element(x_values.begin(), x_values.end());
          int y1 = *std::min_element(y_values.begin(), y_values.end());
          // Find the max
          int x2 = *std::max_element(x_values.begin(), x_values.end());
          int y2 = *std::max_element(y_values.begin(), y_values.end());

          ROS_DEBUG_STREAM_NAMED("perception","x1: " << x1 << " y1: " << y1 << " x2: " << x2 << " y2: " << y2);

          // -------------------------------------------------------------------------------------------------------
          // Expand the ROI by a fudge factor, if possible
          const int FUDGE_FACTOR = 5; // pixels
          if( x1 > FUDGE_FACTOR)
            x1 -= FUDGE_FACTOR;
          if( y1 > FUDGE_FACTOR )
            y1 -= FUDGE_FACTOR;
          if( x2 < image_width - FUDGE_FACTOR )
            x2 += FUDGE_FACTOR;
          if( y2 < image_height - FUDGE_FACTOR )
            y2 += FUDGE_FACTOR;

          ROS_DEBUG_STREAM_NAMED("perception","After Fudge Factor - x1: " << x1 << " y1: " << y1 << " x2: " << x2 << " y2: " << y2);

          // -------------------------------------------------------------------------------------------------------
          // Create ROI parameters
          //        (x1,y1)----------------------
          //       |                            |
          //       |            ROI             |
          //       |                            |
          //       |_____________________(x2,y2)|

          // Create Region of Interest
          int roi_width = x2 - x1;
          int roi_height = y2 - y1;
          cv::Rect region_of_interest = cv::Rect( x1, y1, roi_width, roi_height );
          ROS_DEBUG_STREAM_NAMED("perception","ROI: x " << x1 << " -- y " << y1 << " -- height " << roi_height << " -- width " << roi_width );

          // -------------------------------------------------------------------------------------------------------
          // Find paramters of the block in pixel coordiantes
          int block_center_x = x1 + 0.5*roi_width;
          int block_center_y = y1 + 0.5*roi_height;
          int block_center_z = block_size / 2; // TODO: make this better
          const cv::Point block_center = cv::Point( block_center_x, block_center_y );

          // -------------------------------------------------------------------------------------------------------
          // Create a sub image of just the block
          cv::Point a1 = cv::Point(x1, y1);
          cv::Point a2 = cv::Point(x2, y2);
          cv::rectangle( output_image, a1, a2, cv::Scalar(0, 255, 255), 1, 8);

          // Crop image (doesn't actually copy the data)
          cropped_image = full_input_image_gray(region_of_interest);

          // -------------------------------------------------------------------------------------------------------
          // Detect edges using canny
          ROS_INFO_STREAM_NAMED("perception","Detecting edges using canny");

          // Find edges
          cv::Mat canny_output;
          cv::Canny( cropped_image, canny_output, canny_threshold, canny_threshold*2, 3 );

          // Get mini window stats
          const int mini_width = canny_output.size.p[1];
          const int mini_height = canny_output.size.p[0];
          const cv::Size mini_size = canny_output.size();
          const cv::Point mini_center = cv::Point( mini_width/2, mini_height/2 );

          // Find contours
          vector<vector<cv::Point> > contours;
          vector<cv::Vec4i> hierarchy;
          cv::findContours( canny_output, contours, hierarchy, CV_RETR_TREE, CV_CHAIN_APPROX_SIMPLE, cv::Point(0, 0) );
          ROS_INFO_STREAM_NAMED("perception","Contours");

          // Draw contours
          cv::Mat drawing = cv::Mat::zeros( mini_size, CV_8UC3 );
          ROS_INFO_STREAM_NAMED("perception","Drawing contours");

          // Find the largest contour for getting the angle
          double max_contour_length = 0;
          int max_contour_length_i;
          for( size_t i = 0; i< contours.size(); i++ )
          {
            double contour_length = cv::arcLength( contours[i], false );
            if( contour_length > max_contour_length )
            {
              max_contour_length = contour_length;
              max_contour_length_i = i;
            }
            //ROS_DEBUG_STREAM_NAMED("perception","Contour length = " << contour_length << " of index " << max_contour_length_i);


            cv::Scalar color = cv::Scalar( (30 + i*10) % 255, (30 + i*10) % 255, (30 + i*10) % 255);
            cv::drawContours( drawing, contours, (int)i, color, 1, 8, hierarchy, 0, cv::Point() );
            //drawContours( image, contours, contourIdx, color, thickness, lineType, hierarchy, maxLevel, offset )

          }

          // -------------------------------------------------------------------------------------------------------
          // Copy largest contour to main image
          cv::Scalar color = cv::Scalar( 0, 255, 0 );
          cv::drawContours( output_image, contours, (int)max_contour_length_i, color, 1, 8, hierarchy, 0, a1 );
          //drawContours( image, contours, contourIdx, color, thickness, lineType, hierarchy, maxLevel, offset )

          // -------------------------------------------------------------------------------------------------------
          // Copy largest contour to seperate image
          cv::Mat hough_input = cv::Mat::zeros( mini_size, CV_8UC1 );
          cv::Mat hough_input_color;
          cv::Scalar hough_color = cv::Scalar( 200 );
          cv::drawContours( hough_input, contours, (int)max_contour_length_i, hough_color, 1, 8, hierarchy, 0 );
          cv::cvtColor(hough_input, hough_input_color, CV_GRAY2BGR);

          // -------------------------------------------------------------------------------------------------------
          // Hough Transform
          cv::Mat hough_drawing = cv::Mat::zeros( mini_size, CV_8UC3 );
          std::vector<cv::Vec4i> lines;


          ROS_DEBUG_STREAM_NAMED("perception","hough_rho " << hough_rho << " hough_theta " << hough_theta <<
                                 " theta_converted " << (1/hough_theta)*CV_PI/180 << " hough_threshold " <<
                                 hough_threshold << " hough_minLineLength " << hough_minLineLength <<
                                 " hough_maxLineGap " << hough_maxLineGap );

          cv::HoughLinesP(hough_input, lines, hough_rho, (1/hough_theta)*CV_PI/180, hough_threshold, hough_minLineLength, hough_maxLineGap);

          ROS_WARN_STREAM_NAMED("perception","Found " << lines.size() << " lines");

          std::vector<double> line_angles;

          // Copy detected lines to the drawing image
          for( size_t i = 0; i < lines.size(); i++ )
          {
            cv::Vec4i line = lines[i];
            cv::line( hough_drawing, cv::Point(line[0], line[1]), cv::Point(line[2], line[3]),
                      cv::Scalar(255,255,255), 1, CV_AA);

            // Error check
            if(line[3] - line[1] == 0 && line[2] - line[0] == 0)
            {
              ROS_ERROR_STREAM_NAMED("perception","Line is actually two points at the origin, unable to calculate. TODO: handle better?");
              continue;
            }

            // Find angle
            double line_angle = atan2(line[3] - line[1], line[2] - line[0]); //in radian, degrees: * 180.0 / CV_PI;
            // Reverse angle direction if negative
            if( line_angle < 0 )
            {
              line_angle += CV_PI;
            }
            line_angles.push_back(line_angle);
            ROS_DEBUG_STREAM_NAMED("perception","Hough Line angle: " << line_angle * 180.0 / CV_PI;);
          }

          double block_angle = 0; // the overall result of the block's angle

          // Everything is based on the first angle
          if( line_angles.size() == 0 ) // make sure we have at least 1 angle
          {
            ROS_ERROR_STREAM_NAMED("perception","No lines were found for this cluster, unable to calculate block angle");
          }
          else
          {
            calculateBlockAngle( line_angles, block_angle );
          }

          // -------------------------------------------------------------------------------------------------------
          // Draw chosen angle
          ROS_INFO_STREAM_NAMED("perception","Using block angle " << block_angle*180.0/CV_PI);

          // Draw chosen angle on mini image
          cv::Mat angle_drawing = cv::Mat::zeros( mini_size, CV_8UC3 );
          int line_length = 0.5*double(mini_width); // have the line go 1/4 across the screen
          int new_x = mini_center.x + line_length*cos( block_angle );
          int new_y = mini_center.y + line_length*sin( block_angle );
          ROS_INFO_STREAM("Origin (" << mini_center.x << "," << mini_center.y << ") New (" << new_x << "," << new_y <<
                          ") length " << line_length << " angle " << block_angle <<
                          " mini width " << mini_width << " mini height " << mini_height);
          cv::Point angle_point = cv::Point(new_x, new_y);
          cv::line( angle_drawing, mini_center, angle_point, cv::Scalar(255,255,255), 1, CV_AA);

          // Draw chosen angle on contours image
          cv::line( hough_drawing, mini_center, angle_point, cv::Scalar(255,0, 255), 1, CV_AA);

          // Draw chosen angle on main image
          line_length = 0.75 * double(mini_width); // have the line go 1/2 across the box
          new_x = block_center_x + line_length*cos( block_angle );
          new_y = block_center_y + line_length*sin( block_angle );
          ROS_INFO_STREAM_NAMED("perception",block_center_x << ", " << block_center_y << ", " << new_x << ", " << new_y);
          angle_point = cv::Point(new_x, new_y);
          cv::line( output_image, block_center, angle_point, cv::Scalar(255,0,255), 2, CV_AA);


          // -------------------------------------------------------------------------------------------------------
          // Get world coordinates

          // Find the block's center point
          double world_x1 = xmin+(xside)/2.0;
          double world_y1 = ymin+(yside)/2.0;
          double world_z1 = table_height + block_size / 2;

          // Convert pixel coordiantes back to world coordinates
          double world_x2 = cloud_transformed->at(new_x, new_y).x;
          double world_y2 = cloud_transformed->at(new_x, new_y).y;
          double world_z2 = world_z1; // is this even necessary?

          // Get angle from two world coordinates...
          double world_theta = abs( atan2(world_y2 - world_y1, world_x2 - world_x1) );

          // Attempt to make all angles point in same direction
          makeAnglesUniform( world_theta );

          // -------------------------------------------------------------------------------------------------------
          // GUI Stuff

          // Copy the cluster image to the main image in the top left corner
          if( top_image_overlay_x + mini_width < image_width )
          {
            const int common_height = 42;
            cv::Rect small_roi_row0 = cv::Rect(top_image_overlay_x, common_height*0, mini_width, mini_height);
            cv::Rect small_roi_row1 = cv::Rect(top_image_overlay_x, common_height*1, mini_width, mini_height);
            cv::Rect small_roi_row2 = cv::Rect(top_image_overlay_x, common_height*2, mini_width, mini_height);
            cv::Rect small_roi_row3 = cv::Rect(top_image_overlay_x, common_height*3, mini_width, mini_height);

            drawing.copyTo(              output_image(small_roi_row0) );
            hough_input_color.copyTo(    output_image(small_roi_row1) );
            hough_drawing.copyTo(        output_image(small_roi_row2) );
            angle_drawing.copyTo(        output_image(small_roi_row3) );

            top_image_overlay_x += mini_width;
          }

          // figure out the position and the orientation of the block
          //double angle = atan(block_size/((xside+yside)/2));
          //double angle = atan( (xmaxy - xminy) / (xmax - xmin ) );
          // Then add it to our set
          //addBlock( xmin+(xside)/2.0, ymin+(yside)/2.0, zmax - block_size/2.0, angle);
          //ROS_INFO_STREAM_NAMED("perception","FOUND -> xside: " << xside << " yside: " << yside << " angle: " << block_angle);


          addBlock( world_x1, world_y1, world_z1, world_theta );
          //addBlock( block_center_x, block_center_y, block_center_z, block_angle);
        }
        else
        {