#include #include "nopencv.hpp" using namespace gerbolyze; using namespace gerbolyze::nopencv; /* directions: * 0 * 7 1 * ^ * | * 6 <--- X ---> 2 * | * v * 5 3 * 4 * */ enum Direction { D_N, D_NE, D_E, D_SE, D_S, D_SW, D_W, D_NW }; //const char * const dir_str[8] = { "N", "NE", "E", "SE", "S", "SW", "W", "NW" }; static struct { int x; int y; } dir_to_coords[8] = {{0, -1}, {1, -1}, {1, 0}, {1, 1}, {0, 1}, {-1, 1}, {-1, 0}, {-1, -1}}; static Direction flip_direction[8] = { D_S, D_SW, D_W, D_NW, D_N, D_NE, D_E, D_SE }; static void follow(gerbolyze::nopencv::Image32 img, int start_x, int start_y, Direction initial_direction, int nbd, int connectivity, Polygon &poly) { //cerr << "follow " << start_x << " " << start_y << " | dir=" << dir_str[initial_direction] << " nbd=" << nbd << " conn=" << connectivity << endl; int dir_inc = (connectivity == 4) ? 2 : 1; int probe_x, probe_y; /* homing run: find starting point for algorithm steps below. */ bool found = false; int k; for (k=initial_direction; k= current_direction; k -= dir_inc) { probe_x = center_x + dir_to_coords[k % 8].x; probe_y = center_y + dir_to_coords[k % 8].y; if (k%8 == D_E) flag = true; if (img.at_default(probe_x, probe_y) != 0) { break; } } int set_val = 0; if (flag && img.at_default(center_x+1, center_y) == 0) { img.at(center_x, center_y) = -nbd; set_val = -nbd; } else if (img.at(center_x, center_y) == 1) { img.at(center_x, center_y) = nbd; set_val = nbd; } for (int l = (current_direction + 8 - 2 + 1) / 2 * 2; l > k; l -= dir_inc) { switch (l%8) { case 0: poly.emplace_back(d2p{(double)center_x, (double)center_y}); break; case 2: poly.emplace_back(d2p{(double)center_x+1, (double)center_y}); break; case 4: poly.emplace_back(d2p{(double)center_x+1, (double)center_y+1}); break; case 6: poly.emplace_back(d2p{(double)center_x, (double)center_y+1}); break; } } center_x = probe_x; center_y = probe_y; current_direction = flip_direction[k % 8]; //cerr << " " << center_x << " " << center_y << " / " << dir_str[current_direction] << " -> " << set_val << endl; } while (center_x != start_x || center_y != start_y || current_direction != start_direction); } void gerbolyze::nopencv::find_blobs(gerbolyze::nopencv::Image32 img, gerbolyze::nopencv::ContourCallback cb) { int nbd = 1; Polygon poly; for (int y=0; y= 1 && img.at_default(x+1, y) == 0) { /* hole border starting point */ nbd += 1; follow(img, x, y, D_E, nbd, 4, poly); cb(poly, CP_HOLE); poly.clear(); } } } }