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

Code before:
	}
	return best_fit;
}

unsigned CimbDecoder::decode_symbol(const cv::Mat& cell, unsigned& drift_offset, unsigned& best_distance) const
{
	auto bits = image_hash::fuzzy_ahash(cell);
	std::array<uint64_t,9> hashes = image_hash::extract_fuzzy_ahash(bits);
	/*for (const std::pair<int, int>& drift : CellDrift::driftPairs)
	{
		cv::Rect crop(drift.first + 1, drift.second + 1, 8, 8);
		cv::Mat img = cell(crop);

		hashes.push_back(image_hash::average_hash(img));
	}*/
	return get_best_symbol(hashes, drift_offset, best_distance);
}

unsigned char CimbDecoder::fix_color(unsigned char c, float adjust) const
{
	return (uchar)(c * adjust);
}

double CimbDecoder::check_color_distance(const colorutil::Lab& target_color, const colorutil::Lab& c) const
{
	return colorutil::calculate_CIE76(target_color, c);
}

unsigned CimbDecoder::get_best_color(unsigned char r, unsigned char g, unsigned char b) const
{
	unsigned char max = std::max({r, g, b, uchar(1)});

	float adjust = 255.0 / max;
	r = fix_color(r, adjust);
	g = fix_color(g, adjust);
	b = fix_color(b, adjust);
	colorutil::Lab c = cimbar::convertColor(r, g, b);

	unsigned best_fit = 0;
	double best_distance = 1000000;
	for (int i = 0; i < _numColors; ++i)
	{
		colorutil::Lab target_color = cimbar::getLabColor(i);
		double distance = check_color_distance(target_color, c);
		if (distance < best_distance)
		{
			best_fit = i;
			best_distance = distance;
		}
	}
	return best_fit;

Review comment (performance):
There are three reasons I retreated from CIE76 --

1. trying to squeeze out performance
2. colorutil's Eigen dependency
3. decent results even without it

I think it might be needed for 8 colors, though. If so, it may make a glorious return.

Code after:
	return best_fit;
}

unsigned CimbDecoder::decode_symbol(const cv::Mat& cell, unsigned& drift_offset, unsigned& best_distance) const
{
	auto bits = image_hash::fuzzy_ahash(cell);
	std::array<uint64_t,9> hashes = image_hash::extract_fuzzy_ahash(bits);
	/*for (const std::pair<int, int>& drift : CellDrift::driftPairs)
	{
		cv::Rect crop(drift.first + 1, drift.second + 1, 8, 8);
		cv::Mat img = cell(crop);

		hashes.push_back(image_hash::average_hash(img));
	}*/
	return get_best_symbol(hashes, drift_offset, best_distance);
}

unsigned char CimbDecoder::fix_color(unsigned char c, float adjustUp, unsigned char down) const
{
	c -= down;
	return (uchar)(c * adjustUp);
}

unsigned CimbDecoder::check_color_distance(std::tuple<uchar,uchar,uchar> c, unsigned char r, unsigned char g, unsigned char b) const
{
	return std::pow(get<0>(c) - r, 2) + std::pow(get<1>(c) - g, 2) + std::pow(get<2>(c) - b, 2);
}

unsigned CimbDecoder::get_best_color(unsigned char r, unsigned char g, unsigned char b) const
{
	unsigned char max = std::max({r, g, b});
	unsigned char min = std::min({r, g, b});
	float adjust = 255.0;
	if (max > min)
		adjust /= (max - min);

	r = fix_color(r, adjust, min);
	g = fix_color(g, adjust, min);
	b = fix_color(b, adjust, min);

	unsigned best_fit = 0;
	double best_distance = 1000000;
	for (int i = 0; i < _numColors; ++i)
	{
		std::tuple<uchar,uchar,uchar> c = cimbar::getColor(i);
		unsigned distance = check_color_distance(c, r, g, b);
		if (distance < best_distance)
		{
			best_fit = i;
			best_distance = distance;
		}