#ifndef HOUGH_MACHINE_C #define HOUGH_MACHINE_C #include #include #include #include #include #include "lazy_image.cpp" struct hparam { double theta; double r; int value; }; class HoughMachine { private: LazyImage* original; LazyImage* working_copy; int x_center; int y_center; int n_ang; double d_ang; int n_rad; double d_rad; int* hough_arr; int matching_threshold; int bresenham_orientation_sector; public: HoughMachine(LazyImage* original, LazyImage* working_copy) { this->original = original; this->working_copy = working_copy; this->hough_arr = NULL; }; ~HoughMachine() { this->reset(); }; void reset(void) { this->x_center = 0; this->y_center = 0; this->n_ang = 0; this->d_ang = 0; this->n_rad = 0; this->d_rad = 0; if(this->hough_arr != NULL) { free(this->hough_arr); this->hough_arr = NULL; } this->matching_threshold = 0; this->bresenham_orientation_sector = 0; }; void setMatchingThreshold(int matching_threshold) { // If negative, pixels greater than the absolute value match. // If positive, pixels less than the absolute value match. this->matching_threshold = matching_threshold; }; void run(int a_steps, int r_steps) { this->x_center = this->original->width()/2; this->y_center = this->original->height()/2; this->n_ang = a_steps; this->d_ang = M_PI / this->n_ang; this->n_rad = r_steps; double r_max = sqrt(pow(this->x_center, 2) + pow(this->y_center, 2)); this->d_rad = (2*r_max)/this->n_rad; this->hough_arr = (int*) malloc(sizeof(int) * this->n_ang * this->n_rad); for(int i=0; i< this->n_ang*this->n_rad; i++) this->hough_arr[i] = 0; std::cout << "Hough params: x_center: " << this->x_center << ", y_center: " << this->y_center << std::endl; std::cout << "n_ang: " << this->n_ang << ", d_ang: " << this->d_ang << std::endl; std::cout << "n_rad: " << this->n_rad << ", d_rad: " << this->d_rad << ", r_max: " << r_max << std::endl; this->fillHoughAccumulator(); //this->debugShow(); }; void fillHoughAccumulator() { for(int v=0; voriginal->height(); v++) { for(int u=0; uoriginal->width(); u++) { QColor pixel = QColor::fromRgb(this->original->getPixel(u, v, LazyImage::DEFAULT)); int h, s, l; pixel.getHsl(&h, &s, &l); if(this->matching_threshold > 0) { int threshold = this->matching_threshold; if(l < threshold) this->doPixel(u, v); } else { int threshold = -this->matching_threshold; if(l > threshold) this->doPixel(u, v); } } } }; void doPixel(int u, int v) { int x = u - this->x_center; int y = v - this->y_center; for(int a=0; an_ang; a++) { double theta = this->d_ang * a; int r = (int) qRound( (x*cos(theta) + y*sin(theta)) / this->d_rad ) + this->n_rad / 2; if(r >= 0 && r < this->n_rad) { this->hough_arr[a*this->n_ang+r] += 1; } } }; void drawLines(int n) { // for each value: if == 0 ignore // else check if bigger than all neighbours // if so, put it in the list struct hparam* lines = (struct hparam*) malloc(sizeof(struct hparam) * this->n_ang * this->n_rad); int line = 0; for(int i=0; in_ang*this->n_rad; i++) { int value = this->hough_arr[i]; if(value <= 5) continue; // Ignore small values // TODO: Check neighbours and compare! // Store value if bigger than neighbours int a = i / this->n_ang; int r = i - (a*this->n_ang); double theta = this->d_ang * a; //std::cout << "[" << theta << ", " << r << "] " << value << std::endl; lines[line].r = r; lines[line].theta = theta; lines[line].value = value; line++; } // Now sort it qsort((void*) lines, line, sizeof(struct hparam), HoughMachine::comp); // Draw them double pi_half = M_PI / 2.0; for(int i=0; ix_center; double y = vec_y + this->y_center; std::cout << " vec x: " << x << ", vec y: " << y << std::endl; // create vector for line double vec_target_x = vec_y; double vec_target_y = -vec_x; // normalize it double vec_target_len = sqrt(pow(vec_target_x, 2) + pow(vec_target_y, 2)); vec_target_x = vec_target_x / vec_target_len; vec_target_y = vec_target_y / vec_target_len; // find first border double i = x; double j = y; while(i < this->working_copy->width() && i > 0 && j < this->working_copy->height() && j > 0) { i += vec_target_x; j += vec_target_y; } // find second border int x1 = i; int y1 = j; i = x; j = y; while(i < this->working_copy->width() && i > 0 && j < this->working_copy->height() && j > 0) { i -= vec_target_x; j -= vec_target_y; } int x2 = i; int y2 = j; // TODO: Draw the lines this->otherBresenham(x1, y1, x2, y2); } }; static int comp(const void* a, const void* b) { struct hparam param_a = *((struct hparam*) a); struct hparam param_b = *((struct hparam*) b); int f = param_a.value; int s = param_b.value; if (f > s) return -1; if (f < s) return 1; return 0; } void setPixelDebug(int x, int y, int color=0) { int our_color = QColor::fromRgb(0, 255, 0).rgb(); if(color == 0) color = our_color; //std::cout << " --> SET (" << x << ", " << y << ")" << std::endl; if(x < 0 || y < 0 || x > this->working_copy->width() || y > this->working_copy->height()) return; this->working_copy->getImage()->setPixel(x, y, color); }; void otherBresenham(int x, int y, int x2, int y2) { int width = x2 - x; int height = y2 - y; int dx1 = 0, dy1 = 0, dx2 = 0, dy2 = 0; dx1 = (width < 0) ? -1 : 1; dy1 = (height < 0) ? -1 : 1; dx2 = (width < 0) ? -1 : 1; int longest = abs(width); int shortest = abs(height); if(longest <= shortest) { longest = abs(height); shortest = abs(width); dy2 = (height < 0) ? -1 : 1; dx2 = 0; } int numerator = longest / 2; for(int i=0; i<=longest; i++) { this->setPixelDebug(x, y); numerator += shortest; if(numerator >= longest) { numerator -= longest; x += dx1; y += dy1; } else { x += dx2; y += dy2; } } }; void debugShow() { std::cout << "Dimensions: " << this->n_ang << " x " << this->n_rad << " | " << std::endl; int max_value = 0; for(int i=0; in_ang*this->n_rad; i++) { int current_value = this->hough_arr[i]; if(current_value > max_value) max_value = current_value; } for(int x=0; xn_ang; x++) { for(int y=0; yn_rad; y++) { int value = qRound(255.0*this->hough_arr[x*this->n_ang+y] / max_value); if(value < 0) { std::cout << value << std::endl; value = 0; } if(value > 255) { std::cout << value << std::endl; value = 255; } int color = QColor::fromRgb(value, value, value).rgb(); this->working_copy->getImage()->setPixel(x,y,color); } } }; int getOrientationSector(double dx, double dy) { // Matrix multiplication with rotation matrix pi/8 // // cos(pi/8) -sin(pi/8) // sin(pi/8) cos(pi/8) // TODO: Move these somewhere else! double octangle = M_PI/8; double cosoct = cos(octangle); double sinoct = sin(octangle); double neg_sinoct = -sinoct; // Do matrix multiplication double new_dx = dx * cosoct + dy * neg_sinoct; double new_dy = dx * sinoct + dy * cosoct; int orientation_sector = 0; if(new_dy < 0) { new_dx = -new_dx; new_dy = -new_dy; orientation_sector += 4; } if(new_dx >= 0 && new_dx >= new_dy) orientation_sector += 0; if(new_dx >= 0 && new_dx < new_dy) orientation_sector += 1; if(new_dx < 0 && -new_dx < new_dy) orientation_sector += 2; if(new_dx < 0 && -new_dx >= new_dy) orientation_sector += 3; return orientation_sector; }; void drawLineBresenham(int start_x, int start_y, int end_x, int end_y) { this->bresenham_orientation_sector = this->getOrientationSector(end_x - start_x, end_y - start_y); std::cout << "START LINE: (" << start_x << ", " << start_y << ") -> (" << end_x << ", " << end_y << ") - O: " << this->bresenham_orientation_sector << std::endl; // other implementation for now. this->otherBresenham(start_x, end_x, start_y, end_y); // Now adapt input // Output will be adapted in setPixel() /*switch(this->bresenham_orientation_sector) { case 0: // Going right, nothing to do here this->bresenham(start_x, start_y, end_x, end_y); break; case 1: // Going right, but more up this->bresenham(start_y, start_x, end_y, end_x); break; case 2: // Going left, but more up this->bresenham(start_y, end_x, end_y, start_x); break; case 3: // Going left this->bresenham(end_x, start_y, start_x, end_y); break; case 4: // Going left this->bresenham(end_x, end_y, start_x, start_y); break; case 5: // Going left, but more down this->bresenham(end_y, end_x, start_y, start_x); break; case 6: // Going right, but more down this->bresenham(start_x, end_y, end_x, start_y); break; case 7: // Going right this->bresenham(start_x, end_y, end_x, start_y); break; }*/ }; /*void bresenham(int start_x, int start_y, int end_x, int end_y) { std::cout << "BRESENHAM START LINE: (" << start_x << ", " << start_y << ") -> (" << end_x << ", " << end_y << ")" << std::endl; int x, y; int delta_x, delta_y; int d; int delta_ne, delta_e; x = start_x; y = start_y; delta_x = end_x - start_x; delta_y = end_y - start_y; delta_ne = 2 * (delta_y - delta_x); delta_e = 2 * delta_y; d = 2 * delta_y - delta_x; this->setPixel(start_x, start_y, x, y); while(x < end_x) { if(d >= 0) { d += delta_ne; x++; y++; } else { d += delta_e; x++; } this->setPixel(start_x, start_y, x, y); } std::cout << std::endl; };*/ /*void setPixel(int start_x, int start_y, int dx, int dy) { std::cout << "setPixel(" << start_x << ", " << start_y << ", " << dx << ", " << dy << ")" << std::endl; if(dx > start_x) dx = dx - start_x; else dx = start_x - dx; if(dy > start_y) dy = dy - start_y; else dy = start_y - dy; std::cout << " --> dx: " << dx << ", dy: " << dy << "" << std::endl; int color = QColor::fromRgb(0, 255, 0).rgb(); //TODO: Fix this! This has to happen relative to the center point! :| switch(this->bresenham_orientation_sector) { case 0: // Going right, nothing to do here this->setPixelDebug(start_x + dx, start_y + dy, color); break; case 1: // Going right, but more up this->setPixelDebug(start_x + dy, start_y + dx, color); break; case 2: // Going left, but more up this->setPixelDebug(start_x - dy, start_y + dx, color); break; case 3: // Going left this->setPixelDebug(start_x - dx, start_y + dy, color); break; case 4: // Going left this->setPixelDebug(start_x - dx, start_y - dy, color); break; case 5: // Going left, but more down this->setPixelDebug(start_x + dy, start_y + dx, color); // ok break; case 6: // Going right, but more down this->setPixelDebug(start_x + dy, start_y - dx, color); // ? break; case 7: // Going right this->setPixelDebug(start_x + dx, start_y - dy, color); break; } };*/ }; #endif