Repository: sz3/libcimbar
File: src/lib/extractor/Scanner.h (C/C++)

Code before:
	// get next power of 2 + 1
	// min 3
	v--;
	v |= v >> 1;
	v |= v >> 2;
	v |= v >> 4;
	v |= v >> 8;
	v |= v >> 16;
	return std::max(3U, v + 2);
}

template <typename MAT, typename MAT2>
inline void Scanner::threshold_fast(const MAT& img, MAT2& out)
{
	cv::threshold(img, out, 0, 255, cv::THRESH_BINARY | cv::THRESH_OTSU);
}

template <typename MAT, typename MAT2>
inline void Scanner::threshold_adaptive(const MAT& img, MAT2& out)
{
	unsigned unit = std::min(img.cols, img.rows);
	unit = nextPowerOfTwoPlusOne((unsigned)(unit * 0.05));
	cv::adaptiveThreshold(img, out, 255, cv::ADAPTIVE_THRESH_MEAN_C, cv::THRESH_BINARY, unit, -10);
}

template <typename MAT>
inline cv::Mat Scanner::preprocess_image(const MAT& img, bool fast)
{
	cv::Mat out;
	preprocess_image(img, out, fast);
	return out;
}

template <typename MAT, typename MAT2>
inline void Scanner::preprocess_image(const MAT& img, MAT2& out, bool fast)
{
	MAT temp;
	if (img.channels() >= 3)
		cv::cvtColor(img, temp, cv::COLOR_RGB2GRAY);
	else
		temp = img.clone();

	unsigned unit = std::min(img.cols, img.rows);
	unit = std::max(nextPowerOfTwoPlusOne((unsigned)(unit * 0.002)), 3U);
	cv::GaussianBlur(temp, temp, cv::Size(unit, unit), 0);

	if (fast)
		threshold_fast(temp, out);
	else
		threshold_adaptive(temp, out);
}

Review comment (refactor):
The check here is pretty simple. We run an extract on a freshly encoded image -- no blurring or skewing or any other camera-induced weirdness. We don't even need error correction for an image like this, it's pristine. The corners the scanner finds should be right where we expect them: at the edges of the image.

But if the (essentially random) data pattern is adversarial enough, the scanner will find a "corner" elsewhere, and we can detect/reject this frame as bad.

Code after:
};

inline unsigned Scanner::nextPowerOfTwoPlusOne(unsigned v)
{
	// get next power of 2 + 1
	// min 3
	v--;
	v |= v >> 1;
	v |= v >> 2;
	v |= v >> 4;
	v |= v >> 8;
	v |= v >> 16;
	return std::max(3U, v + 2);
}

template <typename MAT>
inline bool Scanner::will_it_scan(const MAT& unpadded_img)
{
	Scanner scanner(unpadded_img);
	std::vector<Anchor> points = scanner.scan();
	if (points.size() < 4)
		return false;

	constexpr int limit = 50;
	Corners corners(points);
	if (corners.top_left().x() > limit or corners.top_left().y() > limit)
		return false;
	if (corners.top_right().x() < (unpadded_img.cols - limit) or corners.top_right().y() > limit)
		return false;
	if (corners.bottom_left().x() > limit or corners.bottom_left().y() < (unpadded_img.rows - limit))
		return false;
	if (corners.bottom_right().x() < (unpadded_img.cols - limit) or corners.bottom_right().y() < (unpadded_img.rows - limit))
		return false;
	return true;
}

template <typename MAT, typename MAT2>
inline void Scanner::threshold_fast(const MAT& img, MAT2& out)
{
	cv::threshold(img, out, 0, 255, cv::THRESH_BINARY | cv::THRESH_OTSU);
}

template <typename MAT, typename MAT2>
inline void Scanner::threshold_adaptive(const MAT& img, MAT2& out)
{
	unsigned unit = std::min(img.cols, img.rows);
	unit = nextPowerOfTwoPlusOne((unsigned)(unit * 0.05));
	cv::adaptiveThreshold(img, out, 255, cv::ADAPTIVE_THRESH_MEAN_C, cv::THRESH_BINARY, unit, -10);
}

template <typename MAT>