Repository: sz3/libcimbar
File: src/lib/cimb_translator/CimbDecoder.cpp (C++)

Code before:
		std::tuple<int,int,int> rel1 = relative_color(a);
		std::tuple<int,int,int> rel2 = relative_color(b);
		return (
			squared_difference(std::get<0>(rel1), std::get<0>(rel2)) +
			squared_difference(std::get<1>(rel1), std::get<1>(rel2)) +
			squared_difference(std::get<2>(rel1), std::get<2>(rel2))
		);
	}
}

CimbDecoder::CimbDecoder(unsigned symbol_bits, unsigned color_bits, unsigned color_mode, bool dark, uchar ahashThreshold)
	: _symbolBits(symbol_bits)
	, _numSymbols(1 << symbol_bits)
	, _numColors(1 << color_bits)
	, _colorMode(color_mode)
	, _dark(dark)
	, _ahashThreshold(ahashThreshold)
{
	load_tiles();
}

const color_correction& CimbDecoder::get_ccm() const
{
	// testing purposes only.
	// this returning a thread local would be fine, iff we only use it for debugging!
	return _ccm;
}

void CimbDecoder::update_color_correction(cv::Matx<float, 3, 3>&& ccm)
{
	// TODO: threadlocal?
	// because this is dubious to begin with...
	_ccm.update(std::move(ccm));
}

uint64_t CimbDecoder::get_tile_hash(unsigned symbol) const
{
	cv::Mat tile = cimbar::getTile(_symbolBits, symbol, _dark, _numColors);
	return image_hash::average_hash(tile);
}

bool CimbDecoder::load_tiles()
{
	unsigned numTiles = _numSymbols;
	for (unsigned i = 0; i < numTiles; ++i)
		_tileHashes.push_back(get_tile_hash(i));
	return true;
}

unsigned CimbDecoder::get_best_symbol(image_hash::ahash_result<cimbar::Config::cell_size()>& results, unsigned& drift_offset, unsigned& best_distance, unsigned cooldown) const
{

Review comment (bug):
The only interesting code change on this branch.

We've had a subtle(?) race condition in the CFC app ever since I introduced color correction -- this `CimbDecoder` object is shared across threads, which means that updating the ccm matrix is asking for trouble.

I could pass it around as a function param (implicitly threadlocal), but I want to experiment with static threadlocal a bit -- it might be useful for the `Config` object...

Code after:
		std::tuple<int,int,int> rel1 = relative_color(a);
		std::tuple<int,int,int> rel2 = relative_color(b);
		return (
			squared_difference(std::get<0>(rel1), std::get<0>(rel2)) +
			squared_difference(std::get<1>(rel1), std::get<1>(rel2)) +
			squared_difference(std::get<2>(rel1), std::get<2>(rel2))
		);
	}
}

CimbDecoder::CimbDecoder(unsigned symbol_bits, unsigned color_bits, unsigned color_mode, bool dark, uchar ahashThreshold)
	: _symbolBits(symbol_bits)
	, _numSymbols(1 << symbol_bits)
	, _numColors(1 << color_bits)
	, _colorMode(color_mode)
	, _dark(dark)
	, _ahashThreshold(ahashThreshold)
{
	load_tiles();
}

// protected
color_correction& CimbDecoder::internal_ccm() const
{
	static thread_local color_correction _ccm;
	return _ccm;
}

// public
const color_correction& CimbDecoder::get_ccm() const
{
	// testing/debugging purposes only!!!!
	return internal_ccm();
}

void CimbDecoder::update_color_correction(cv::Matx<float, 3, 3>&& ccm)
{
	internal_ccm().update(std::move(ccm));
}

uint64_t CimbDecoder::get_tile_hash(unsigned symbol) const
{
	cv::Mat tile = cimbar::getTile(_symbolBits, symbol, _dark, _numColors);
	return image_hash::average_hash(tile);
}

bool CimbDecoder::load_tiles()
{
	unsigned numTiles = _numSymbols;
	for (unsigned i = 0; i < numTiles; ++i)
		_tileHashes.push_back(get_tile_hash(i));