CG2_Tasks/hough_machine.cpp

278 lines
7.8 KiB
C++
Raw Normal View History

#ifndef HOUGH_MACHINE_C
#define HOUGH_MACHINE_C
#include <QtGlobal>
#include <QMainWindow>
#include <QColor>
#include <iostream>
#include <math.h>
#include "lazy_image.cpp"
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;
2016-01-07 09:45:52 +01:00
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; v<this->original->height(); v++) {
for(int u=0; u<this->original->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;
std::cout << "Comparing " << l << " < " << threshold << std::endl;
if(l < threshold) this->doPixel(u, v);
} else {
int threshold = -this->matching_threshold;
std::cout << "Comparing " << l << " > " << threshold << std::endl;
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; a<this->n_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) {
// TODO: Sort stuff in hough_arr by value, get the n top values and draw them using bresenham.
// put all of them into a custom struct (a, r, value). Now sort these fuckers!
};
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);
// 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(end_y, start_x, start_y, end_x);
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) {
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(x, y);
while(x < end_x) {
if(d >= 0) {
d += delta_ne; x++; y++;
} else {
d += delta_e; x++;
}
this->setPixel(x, y);
}
};
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 setPixel(int x, int y) {
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->working_copy->getImage()->setPixel(x, y, color);
break;
case 1:
// Going right, but more up
this->working_copy->getImage()->setPixel(y, x, color);
break;
case 2:
// Going left, but more up
this->working_copy->getImage()->setPixel(-y, x, color);
break;
case 3:
// Going left
this->working_copy->getImage()->setPixel(-x, y, color);
break;
case 4:
// Going left
this->working_copy->getImage()->setPixel(-x, -y, color);
break;
case 5:
// Going left, but more down
this->working_copy->getImage()->setPixel(-y, -x, color);
break;
case 6:
// Going right, but more down
this->working_copy->getImage()->setPixel(y, -x, color);
break;
case 7:
// Going right
this->working_copy->getImage()->setPixel(x, -y, color);
break;
}
};
void debugShow() {
std::cout << "Dimensions: " << this->n_ang << " x " << this->n_rad << " | " << std::endl;
int max_value = 0;
for(int i=0; i<this->n_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; x<this->n_ang; x++) {
for(int y=0; y<this->n_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);
}
}
};
};
#endif