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

Code before:
	{
		static const cv::Mat k = (cv::Mat_<float>(3,3) <<  -1, -1, -1, -1, 8.5, -1, -1, -1, -1);
		return k;
	}

	template <typename MAT>
	void sharpenSymbolGrid(const MAT& img, cv::Mat& out)
	{
		cv::filter2D(img, out, -1, kernel());
	}

	template <typename MAT>
	cv::Mat preprocessSymbolGrid(const MAT& img, bool needs_sharpen, bool needs_threshold)
	{
		cv::Mat symbols;
		if (needs_sharpen)
		{
			sharpenSymbolGrid(img, symbols);
			cv::cvtColor(symbols, symbols, cv::COLOR_BGR2GRAY);
		}
		else
			cv::cvtColor(img, symbols, cv::COLOR_BGR2GRAY);

		if (needs_threshold)
			cv::adaptiveThreshold(symbols, symbols, 255, cv::ADAPTIVE_THRESH_MEAN_C, cv::THRESH_BINARY, 3, 0);
		return symbols;
	}
}

CimbReader::CimbReader(const cv::Mat& img, const CimbDecoder& decoder, bool needs_sharpen)
    : _image(img)
    , _cellSize(Config::cell_size() + 2)
    , _positions(Config::cell_spacing(), Config::num_cells(), Config::cell_size(), Config::corner_padding())
    , _decoder(decoder)
{
	_grayscale = preprocessSymbolGrid(img, needs_sharpen, decoder.expects_binary_threshold());
}

CimbReader::CimbReader(const cv::UMat& img, const CimbDecoder& decoder, bool needs_sharpen)
    : _image(img.getMat(cv::ACCESS_READ))
    , _cellSize(Config::cell_size() + 2)
    , _positions(Config::cell_spacing(), Config::num_cells(), Config::cell_size(), Config::corner_padding())
    , _decoder(decoder)
{
	_grayscale = preprocessSymbolGrid(img, needs_sharpen, decoder.expects_binary_threshold());
}

unsigned CimbReader::read(unsigned& bits)
{
	if (_positions.done())
		return 0;

Review comment (suggestion):
No `needs_threshold` check. The results are good enough that we'll just do it. `3` or `5` for the block size is debatable. Larger seems to get consistently worse results.

Code after:
namespace {
	cv::Mat kernel()
	{
		static const cv::Mat k = (cv::Mat_<float>(3,3) <<  -1, -1, -1, -1, 8.5, -1, -1, -1, -1);
		return k;
	}

	template <typename MAT>
	void sharpenSymbolGrid(const MAT& img, cv::Mat& out)
	{
		cv::filter2D(img, out, -1, kernel());
	}

	template <typename MAT>
	bitbuffer preprocessSymbolGrid(const MAT& img, bool needs_sharpen)
	{
		cv::Mat symbols;
		if (needs_sharpen)
		{
			sharpenSymbolGrid(img, symbols);
			cv::cvtColor(symbols, symbols, cv::COLOR_BGR2GRAY);
		}
		else
			cv::cvtColor(img, symbols, cv::COLOR_BGR2GRAY);

		cv::adaptiveThreshold(symbols, symbols, 255, cv::ADAPTIVE_THRESH_MEAN_C, cv::THRESH_BINARY, 3, 0);

		bitbuffer bb(1024*128);
		bitmatrix::mat_to_bitbuffer(symbols, bb.get_writer());
		return bb;
	}
}

CimbReader::CimbReader(const cv::Mat& img, const CimbDecoder& decoder, bool needs_sharpen)
    : _image(img)
    , _cellSize(Config::cell_size() + 2)
    , _positions(Config::cell_spacing(), Config::num_cells(), Config::cell_size(), Config::corner_padding())
    , _decoder(decoder)
{
	_grayscale = preprocessSymbolGrid(img, needs_sharpen);
}

CimbReader::CimbReader(const cv::UMat& img, const CimbDecoder& decoder, bool needs_sharpen)
    : _image(img.getMat(cv::ACCESS_READ))
    , _cellSize(Config::cell_size() + 2)
    , _positions(Config::cell_spacing(), Config::num_cells(), Config::cell_size(), Config::corner_padding())
    , _decoder(decoder)
{
	_grayscale = preprocessSymbolGrid(img, needs_sharpen);
}