一. 项目进展:
1.将二进制文件编码成二维码,108×108像素矩阵
2.解码二维码生成二进制文件
3.利用OpenCV生成视频,而不是命令行直接生成
4.利用海明码进行校验
5.对拍摄的图片进行轻量级旋转并截取二维码
二. 下一步计划:
1..测试程序,分析传输率
2.提高拍摄图片的解码正确率
3.封装程序
三. 技术尝试:
尝试使用奇偶校验,后改为海明校验。
生成二维码代码:
void encode::BuildDataZone(char* Data)
{
int k = 0,p=0;
for (int i=0;i<=15;i++)
{
for (int j=0;j<=71;j++)
{
mat.at<Vec3b>(QuietZoneSize + i, FinderPatternSize + QuietZoneSize + j) = v3b[(((*Data) & 0x80) == 0x80) ? 0 : 7];
(*Data) <<= 1;
p++;
if (p % 8 == 0)Data++;
}
}
for (int i = 0; i <= 1; i++)
{
for (int j = 0; j <= 87; j++)
{
mat.at<Vec3b>(FinderPatternSize + QuietZoneSize + i, FinderPatternSize + QuietZoneSize + j) = v3b[((Data[k] & 0x80) == 0x80) ? 0 : 7];
(*Data) <<= 1;
p++;
if (p % 8 == 0)Data++;
}
}
for (int i = 0; i <= 69; i++)
{
for (int j = 0; j <= 103; j++)
{
mat.at<Vec3b>(FinderPatternSize + QuietZoneSize + 2 + i, QuietZoneSize + j) = v3b[((Data[k] & 0x80) == 0x80) ? 0 : 7];
(*Data) <<= 1;
p++;
if (p % 8 == 0)Data++;
}
}
for (int i = 0; i <= 15; i++)
{
for (int j = 0; j <= 87; j++)
{
mat.at<Vec3b>(FinderPatternSize + QuietZoneSize + 72 + i, FinderPatternSize+QuietZoneSize + j) = v3b[((Data[k] & 0x80) == 0x80) ? 0 : 7];
(*Data) <<= 1;
p++;
if (p % 8 == 0)Data++;
}
}
return;
}
解码二维码代码:
#define _CRT_SECURE_NO_WARNINGS 1
#include <iostream>
#include <fstream>
#include "encode.h"
#include <opencv2/core.hpp>
#include <opencv2/imgcodecs.hpp>
#include <opencv2/highgui.hpp>
#include <opencv2/imgproc.hpp>
#include <iostream>
#include <time.h>
#include <set>
using namespace std;
int* firstBlack(cv::Mat& image)
{
int* p = new int[2];
for (int i = 0; i < image.rows; ++i)
{
for (int j = 0; j < image.cols; ++j)
{
if (image.at<unsigned char>(i, j) <= 15)
{
p[0] = i;
p[1] = j;
return p;
}
}
}
}
int width(int x, int y, cv::Mat& image)
{
while (1)
{
++x;
if (image.at<unsigned char>(y, x) >= 15)
break;
}
return x - 1;
}
int main()
{
ofstream binaryFile("binary_output.bin", ios::binary);
cv::Mat image = cv::imread("qrcode.png");
cv::Mat grayImage;
cv::cvtColor(image, grayImage, cv::COLOR_BGR2GRAY);
cv::Mat binaryImage;
cv::threshold(grayImage, binaryImage, 127, 255, cv::THRESH_BINARY | cv::THRESH_OTSU); // 使用OTSU方法自动计算阈值
imshow("bits", binaryImage);
int* temp = firstBlack(binaryImage);
int firstx = temp[1], firsty = temp[0];
int tempx = width(firstx, firsty, binaryImage);
int wide = tempx - firstx + 1;
int single = wide / 14;
int i = firsty;
for (; i <= firsty + single * 14; i += single)
{
for (int j = tempx + single; j <= firstx + single * 88; j += single)
{
if (binaryImage.at<unsigned char>(i, j) <= 15) {
binaryFile.write("1", 1);
cout << '1';
}
else {
binaryFile.write("0", 1);
cout << '0';
}
}
cout << endl;
}
for (; i < firsty + single * 88; i += single)
{
for (int j = firstx; j <= firstx + single * 103; j += single)
{
if (binaryImage.at<unsigned char>(i, j) <= 15) {
binaryFile.write("1", 1);
cout << '1';
}
else {
binaryFile.write("0", 1);
cout << '0';
}
}
cout << endl;
}
for (; i <= firsty + single * 103; i += single)
{
for (int j = tempx + single; j <= firstx + single * 104; j += single)
{
if (binaryImage.at<unsigned char>(i, j) <= 15) {
binaryFile.write("1", 1);
cout << '1';
}
else {
binaryFile.write("0", 1);
cout << '0';
}
}
cout << endl;
}
binaryFile.close();
return 0;
}
OpenCV生成视频:
#include"picvideo.h"
namespace picvideo {
//将元组内各类图片转化为视频
void pic2video(vector<Mat>& src_ims)
{
string name2 = "test.avi";
cout << "请输入编码后的视频文件名,例如“test.avi”:" << endl;
cin >> name2;
int frame_rate = 15;
//cout << "请输入视频帧率:" << endl;
//cin >> frame_rate;
VideoWriter video(name2, VideoWriter::fourcc('M', 'P', '4', 'V'), frame_rate, Size(1000, 1000), false);
for (size_t i = 0; i < src_ims.size(); i++)
{
Mat image = src_ims[i].clone();
// 流操作符,把图片传入视频
video << image;
}
}
//将视频逐帧提取进入元组成为Mat类对象
void video2pic(string path, vector<Mat>& src_ims)
{
VideoCapture capture(path);
Mat frame;
while (true) {
//一帧一帧读
capture >> frame;
if (frame.empty()) {
break;
}
else src_ims.push_back(frame.clone());
}
}
//用于播放视频内容,参数为当目录下文件名字
void videoshow(string path)
{
VideoCapture capture(path);
while (1)
{
//frame存储每一帧图像
Mat frame;
//读取当前帧
capture >> frame;
//播放完退出
if (frame.empty()) {
printf("播放完成\n");
break;
}
//显示当前视频
imshow("读取视频", frame);
//延时300ms
waitKey(300);
}
}
}