diff --git a/src/lib/cimb_translator/CellDrift.cpp b/src/lib/cimb_translator/CellDrift.cpp index bec89b72..53ffd319 100644 --- a/src/lib/cimb_translator/CellDrift.cpp +++ b/src/lib/cimb_translator/CellDrift.cpp @@ -6,8 +6,8 @@ namespace { } CellDrift::CellDrift(int x, int y) - : _x(x) - , _y(y) + : _x(x) + , _y(y) {} int CellDrift::x() const @@ -29,3 +29,18 @@ void CellDrift::updateDrift(int dx, int dy) _y = std::min(_y, _limit); _y = std::max(_y, 0-_limit); } + +// static +uint8_t CellDrift::calculate_cooldown(uint8_t previous, uint8_t idx) +{ + // previous xor idx == 6?? + if (previous == 1 and idx == 7) + return 0xFF; + if (previous == 3 and idx == 5) + return 0xFF; + if (previous == 5 and idx == 3) + return 0xFF; + if (previous == 1 and idx == 7) + return 0xFF; + return idx; +} diff --git a/src/lib/cimb_translator/CellDrift.h b/src/lib/cimb_translator/CellDrift.h index d0f37661..44d5732d 100644 --- a/src/lib/cimb_translator/CellDrift.h +++ b/src/lib/cimb_translator/CellDrift.h @@ -10,9 +10,11 @@ class CellDrift CellDrift(int x=0, int y=0); inline static const std::array, 9> driftPairs = {{ - {-1, -1}, {0, -1}, {1, -1}, {-1, 0}, {0, 0}, {1, 0}, {-1, 1}, {0, 1}, {1, 1} + {-1, -1}, {0, -1}, {1, -1}, {-1, 0}, {0, 0}, {1, 0}, {-1, 1}, {0, 1}, {1, 1} }}; + static uint8_t calculate_cooldown(uint8_t previous, uint8_t idx); + int x() const; int y() const; diff --git a/src/lib/cimb_translator/CimbDecoder.cpp b/src/lib/cimb_translator/CimbDecoder.cpp index da0f38fa..b77bd373 100644 --- a/src/lib/cimb_translator/CimbDecoder.cpp +++ b/src/lib/cimb_translator/CimbDecoder.cpp @@ -79,7 +79,7 @@ bool CimbDecoder::load_tiles() return true; } -unsigned CimbDecoder::get_best_symbol(image_hash::ahash_result& results, unsigned& drift_offset, unsigned& best_distance) const +unsigned CimbDecoder::get_best_symbol(image_hash::ahash_result& results, unsigned& drift_offset, unsigned& best_distance, unsigned cooldown) const { drift_offset = 0; unsigned best_fit = 0; @@ -91,6 +91,11 @@ unsigned CimbDecoder::get_best_symbol(image_hash::ahash_result& results, unsigne // 8, 0, 2, 6 == corners. for (auto&& [drift_idx, h] : results) { + // skip over this drift_idx if it matches cooldown + // we could be more clever to check for corners, but for now this is fine + // ~0U is "unset" + if (drift_idx == cooldown and drift_idx != 4) // don't skip the center, obvs + continue; for (unsigned i = 0; i < _tileHashes.size(); ++i) { unsigned distance = image_hash::hamming_distance(h, _tileHashes[i]); @@ -107,16 +112,16 @@ unsigned CimbDecoder::get_best_symbol(image_hash::ahash_result& results, unsigne return best_fit; } -unsigned CimbDecoder::decode_symbol(const cv::Mat& cell, unsigned& drift_offset, unsigned& best_distance) const +unsigned CimbDecoder::decode_symbol(const cv::Mat& cell, unsigned& drift_offset, unsigned& best_distance, unsigned cooldown) const { image_hash::ahash_result results = image_hash::fuzzy_ahash(cell, _ahashThreshold, image_hash::ahash_result::FAST); return get_best_symbol(results, drift_offset, best_distance); } -unsigned CimbDecoder::decode_symbol(const bitmatrix& cell, unsigned& drift_offset, unsigned& best_distance) const +unsigned CimbDecoder::decode_symbol(const bitmatrix& cell, unsigned& drift_offset, unsigned& best_distance, unsigned cooldown) const { image_hash::ahash_result results = image_hash::fuzzy_ahash(cell, image_hash::ahash_result::FAST); - return get_best_symbol(results, drift_offset, best_distance); + return get_best_symbol(results, drift_offset, best_distance, cooldown); } std::tuple CimbDecoder::fix_color(std::tuple c, float adjustUp, float down) const diff --git a/src/lib/cimb_translator/CimbDecoder.h b/src/lib/cimb_translator/CimbDecoder.h index 517a983d..4b3262ed 100644 --- a/src/lib/cimb_translator/CimbDecoder.h +++ b/src/lib/cimb_translator/CimbDecoder.h @@ -16,9 +16,9 @@ class CimbDecoder void update_color_correction(cv::Matx&& ccm); - unsigned get_best_symbol(image_hash::ahash_result& results, unsigned& drift_offset, unsigned& best_distance) const; - unsigned decode_symbol(const cv::Mat& cell, unsigned& drift_offset, unsigned& best_distance) const; - unsigned decode_symbol(const bitmatrix& cell, unsigned& drift_offset, unsigned& best_distance) const; + unsigned get_best_symbol(image_hash::ahash_result& results, unsigned& drift_offset, unsigned& best_distance, unsigned cooldown=~0U) const; + unsigned decode_symbol(const cv::Mat& cell, unsigned& drift_offset, unsigned& best_distance, unsigned cooldown=~0U) const; + unsigned decode_symbol(const bitmatrix& cell, unsigned& drift_offset, unsigned& best_distance, unsigned cooldown=~0U) const; unsigned get_best_color(float r, float g, float b) const; unsigned decode_color(const Cell& cell) const; diff --git a/src/lib/cimb_translator/CimbReader.cpp b/src/lib/cimb_translator/CimbReader.cpp index e1695954..facfadce 100644 --- a/src/lib/cimb_translator/CimbReader.cpp +++ b/src/lib/cimb_translator/CimbReader.cpp @@ -119,18 +119,18 @@ unsigned CimbReader::read(PositionData& pos) return 0; // need coordinate, index, and drift from next position - auto [i, xy, drift] = _positions.next(); + auto [i, xy, drift, cooldown] = _positions.next(); int x = xy.first + drift.x(); int y = xy.second + drift.y(); bitmatrix cell(_grayscale, _image.cols, _image.rows, x-1, y-1); unsigned drift_offset = 0; unsigned error_distance; - unsigned bits = _decoder.decode_symbol(cell, drift_offset, error_distance); + unsigned bits = _decoder.decode_symbol(cell, drift_offset, error_distance, cooldown); std::pair best_drift = CellDrift::driftPairs[drift_offset]; drift.updateDrift(best_drift.first, best_drift.second); - _positions.update(i, drift, error_distance); + _positions.update(i, drift, error_distance, CellDrift::calculate_cooldown(cooldown, drift_offset)); pos.i = i; pos.x = x + best_drift.first; diff --git a/src/lib/cimb_translator/FloodDecodePositions.cpp b/src/lib/cimb_translator/FloodDecodePositions.cpp index 19f32a92..c0e8c7e5 100644 --- a/src/lib/cimb_translator/FloodDecodePositions.cpp +++ b/src/lib/cimb_translator/FloodDecodePositions.cpp @@ -21,7 +21,7 @@ void FloodDecodePositions::reset() for (unsigned i = 0; i < _positions.size(); ++i) { _remaining.push_back(true); - _instructions.push_back({CellDrift(), 0xFF}); + _instructions.push_back({CellDrift(), 0xFF, 0xFF}); } // seed @@ -58,14 +58,14 @@ FloodDecodePositions::iter FloodDecodePositions::next() needsDecode = false; ++_count; - auto [drift, __] = _instructions[i]; - return {i, _positions[i], drift}; + auto [drift, __, cooldown] = _instructions[i]; + return {i, _positions[i], drift, cooldown}; } - return {0, {0, 0}, CellDrift()}; + return {0, {0, 0}, CellDrift(), 0xFF}; } -int FloodDecodePositions::update(unsigned index, const CellDrift& drift, unsigned error_distance) +int FloodDecodePositions::update(unsigned index, const CellDrift& drift, unsigned error_distance, uint8_t cooldown) { std::array adj = _cellFinder.find(index); for (int next : adj) @@ -73,9 +73,9 @@ int FloodDecodePositions::update(unsigned index, const CellDrift& drift, unsigne if (next < 0 or !_remaining[next]) continue; decode_instructions& di = _instructions[next]; - if (di.second <= error_distance) + if (std::get<1>(di) <= error_distance) continue; - di = {drift, error_distance}; + di = {drift, error_distance, cooldown}; _heap.push({next, error_distance}); } return 0; diff --git a/src/lib/cimb_translator/FloodDecodePositions.h b/src/lib/cimb_translator/FloodDecodePositions.h index 44b608ab..e0b09155 100644 --- a/src/lib/cimb_translator/FloodDecodePositions.h +++ b/src/lib/cimb_translator/FloodDecodePositions.h @@ -12,8 +12,8 @@ class FloodDecodePositions { public: - using iter = std::tuple; - using decode_instructions = std::pair; // drift, best_prio + using iter = std::tuple; + using decode_instructions = std::tuple; // drift, best_prio, cooldown_pos using decode_prio = std::tuple; // index, prio class PrioCompare @@ -33,7 +33,7 @@ class FloodDecodePositions bool done() const; iter next(); - int update(unsigned index, const CellDrift& drift, unsigned error_distance); + int update(unsigned index, const CellDrift& drift, unsigned error_distance, uint8_t cooldown); protected: unsigned _index; diff --git a/src/lib/cimb_translator/test/FloodDecodePositionsTest.cpp b/src/lib/cimb_translator/test/FloodDecodePositionsTest.cpp index f0febb7b..a8f8fe17 100644 --- a/src/lib/cimb_translator/test/FloodDecodePositionsTest.cpp +++ b/src/lib/cimb_translator/test/FloodDecodePositionsTest.cpp @@ -23,13 +23,14 @@ TEST_CASE( "FloodDecodePositionsTest/testSimple", "[unit]" ) unsigned i; CellPositions::coordinate xy; CellDrift drift; + uint8_t cooldown; // validate seed points unsigned count = 0; for (int c = 0; c < 4; ++c) { // 0 - std::tie(i, xy, drift) = cells.next(); + std::tie(i, xy, drift, cooldown) = cells.next(); assertEquals(0, drift.x()); assertEquals(0, drift.y()); @@ -38,25 +39,25 @@ TEST_CASE( "FloodDecodePositionsTest/testSimple", "[unit]" ) assertEquals(62, xy.first); assertEquals(8, xy.second); drift.updateDrift(1, 1); - cells.update(i, drift, 1); + cells.update(i, drift, 1, cooldown); } else if (i == 99) { assertEquals(953, xy.first); assertEquals(8, xy.second); - cells.update(i, drift, 2); + cells.update(i, drift, 2, cooldown); } else if (i == 12300) { assertEquals(62, xy.first); assertEquals(1007, xy.second); - cells.update(i, drift, 2); + cells.update(i, drift, 2, cooldown); } else if (i == 12399) { assertEquals(953, xy.first); assertEquals(1007, xy.second); - cells.update(i, drift, 2); + cells.update(i, drift, 2, cooldown); } else FAIL("i ?= " << i); @@ -68,7 +69,7 @@ TEST_CASE( "FloodDecodePositionsTest/testSimple", "[unit]" ) // we did "update(..., 1) for index=1. So the next cells should be the ones adjacent to 0: 1, 100. for (int c = 0; c < 2; ++c) { - std::tie(i, xy, drift) = cells.next(); + std::tie(i, xy, drift, cooldown) = cells.next(); if (i == 1) { assertEquals(71, xy.first); @@ -85,7 +86,7 @@ TEST_CASE( "FloodDecodePositionsTest/testSimple", "[unit]" ) assertEquals(1, drift.x()); assertEquals(1, drift.y()); - cells.update(i, drift, 3); + cells.update(i, drift, 3, cooldown); remainingPos.erase(i); ++count; } @@ -93,8 +94,8 @@ TEST_CASE( "FloodDecodePositionsTest/testSimple", "[unit]" ) // as for the rest... we'll just make sure we hit them all while (!cells.done()) { - std::tie(i, xy, drift) = cells.next(); - cells.update(i, drift, 1); + std::tie(i, xy, drift, cooldown) = cells.next(); + cells.update(i, drift, 1, cooldown); remainingPos.erase(i); ++count; } diff --git a/src/lib/image_hash/ahash_result.h b/src/lib/image_hash/ahash_result.h index 46063575..5acb5c5c 100644 --- a/src/lib/image_hash/ahash_result.h +++ b/src/lib/image_hash/ahash_result.h @@ -20,7 +20,7 @@ class ahash_result // 5, 7, 3, 1 == sides. // 8, 0, 2, 6 == corners. // mode=FAST will discard the corner checks. - static constexpr std::array _ORDER = {4, 5, 7, 3, 1, 8, 0, 2, 6}; + static constexpr std::array _ORDER = {4, 5, 7, 3, 1, 8, 0, 2, 6}; public: class iterator @@ -31,9 +31,9 @@ class ahash_result , _i(i) {} - std::pair operator*() + std::pair operator*() { - int idx = _hr._ORDER[_i]; + unsigned idx = _hr._ORDER[_i]; return {idx, _hr._results[idx]}; }