前言
在之前的文章中,已经实现了数据层面上的二维码的生成,但实际上这并不能实际应用在各种场景之中。而这篇文章就是其从数据到应用的场景之一。
原理
根据之前的文章,我们可以得到二维码位图的边长,而为了转化为图片,我们需要知道二维码图片的像素大小;而为了知道二维码图片的像素大小,就需要知道一个位图的点的像素大小为多少。
QRCode qr("csdn-lisenlingood");
size_t len = qr.getLen(),pixlen = len * pix_size;
在opencv之中,常用于图片生成的有"cv::Mat::ones",其可以生成全白的图片,像素大小为二维码图片像素大小加上边框的空余(可为0)
// CV_32F为选择的图片格式,这便于我们设置图片中的某个像素点为黑色,而RGB模式需要分别设置RGB的值
// 后续需要进行转换到RGB模式的图片上
cv::Mat img = cv::Mat::ones(pixlen + margin * 2, pixlen + margin * 2, CV_32F);
在设置完成空白图片之后,就需要对图片进行“涂黑”处理了。
在处理过程中,需要考虑怎么“涂黑”一个位图的点,假设我们有一个需要涂黑的点,其像素大小为4,那么可以想象得到一个黑色的、边长为4的正方形。假设其在位图的(i,j)点上,也就是在图片的(i * pix_size + margin,j * pix_size + margin)点上,那么有
因此有
for (size_t k = 0; k < pix_size; k++)
for (size_t l = 0; l < pix_size; l++)
img.at<float>(i * pix_size + k + margin, j * pix_size + l + margin) = 0;
在此之上,对所有位图点遍历画图有
for (int i = 0; i < len; i++)
for (int j = 0; j < len; j++)
if (qr.get(i, j))
for (size_t k = 0; k < _pix_size; k++)
for (size_t l = 0; l < _pix_size; l++)
img.at<float>(i * _pix_size + k + _margin, j * _pix_size + l + _margin) = 0;
画完图之后,进行转换之后输出,有
qrm.convertTo(res, CV_8U, 255.0);
cv::imwrite("qrcode.png", img);
附录
上述内容以函数进行解释得到
cv::Mat qr2png(QRCode& _qr, size_t _pix_size,size_t _margin)
{
int len = _qr.getLen(),pixlen = len * _pix_size;
cv::Mat qrm = cv::Mat::ones(pixlen + _margin * 2, pixlen + _margin * 2, CV_32F), res;
for (int i = 0; i < len; i++)
for (int j = 0; j < len; j++)
if (_qr.get(i, j))
for (size_t k = 0; k < _pix_size; k++)
for (size_t l = 0; l < _pix_size; l++)
qrm.at<float>(i * _pix_size + k + _margin, j * _pix_size + l + _margin) = 0;
qrm.convertTo(res, CV_8U, 255.0);
cv::imwrite("qrcode.png", res);
return res;
}