单张图像内存大,大批量图像会占用大量的内存。如果对图像中的固定ROI区域进行检测,可以将图像的roi区域转为json文件以达到降低内存的目的。利用Qt的逐个读取像素的方法速度太慢,因此采用Base64编码来转换成Json格式。
Json文本格式
"x","y","height","width"分别代表roi区域在原图像的位置,"image"是base64编码后的ROI图像。
{
"ROIs": [
{
"height": 1000,
"image": "iVBORw0KGgoAAAANSUhEUgAAA+....",
"width": 1000,
"x": 200,
"y": 200
},
{
"height": 1000,
"image": "iVBORw0KGgoAAAANSUhEUgAAA....,
"width": 1000,
"x": 2000,
"y": 2000
}
]
}
Image转Json
思路:
(1)在创建了两个蓝色矩形区域,方便检查Json转Image的时候是否有错误。并设置ROI区域矩形的范围,
(2)对每个ROI区域单独创建QJsonObject对象,将x,y,width,height以及base64编码后的roi图像赋给QJsonObject对象。
(3)创建一个QJsonArray,循环遍历每个ROI区域并将每个ROI区域的QJsonObject对象传给QJsonArray对象。
(4)最后,通过创建QJsonDocument对象将json文件写入本地。
void MyGraphicsView::on_btn_action_ImageToJson()
{
//创建roi区域
QRect roi1(200, 200, 1000, 1000);
QRect roi2(2000, 2000, 1000, 1000);
QList<QRect> rois;
rois.append(roi1);
rois.append(roi2);
// 创建4000的QImage,使用RGB888格式
QImage blackImage(4000, 4000, QImage::Format_RGB888);
// 将图像填充为纯黑色
blackImage.fill(QColor(Qt::black).rgb());
//绘制矩形
QPainter painter(&blackImage);
painter.setPen(Qt::red);
painter.setBrush(Qt::blue);
painter.drawRect(QRectF(300, 300, 800, 800));
painter.drawRect(QRectF(2100, 2100, 800, 800));
// 创建一个QElapsedTimer对象
QElapsedTimer timer;
// 启动计时器
timer.start();
//将图像的多个roi区域保存成json文件
saveROIsToJson(blackImage, rois, "./black.json");
// 计算经过的时间(毫秒)
qint64 elapsedTime = timer.elapsed();
qDebug() << "Image to Json time"<<elapsedTime ;
}
// 保存ROI信息和Base64图像到JSON文件
void MyGraphicsView::saveROIsToJson(const QImage& image, const QList<QRect>& rois, const QString& outputFileName)
{
QJsonArray jsonRoiArray;
// 遍历每个ROI区域,将它们的信息和图像Base64编码保存到JSON中
for (const QRect& roi : rois)
{
if (roi.isValid()) {
QJsonObject jsonRoi;
//保存ROI区域的范围
jsonRoi["x"] = roi.x();
jsonRoi["y"] = roi.y();
jsonRoi["width"] = roi.width();
jsonRoi["height"] = roi.height();
//对ROI区域的像素编码
QImage roiImage = image.copy(roi);
jsonRoi["image"] = imageToBase64(roiImage);
jsonRoiArray.append(jsonRoi);
}
}
// 创建JSON文档并保存到文件
QJsonObject root;
root["ROIs"] = jsonRoiArray;
QJsonDocument jsonDoc(root);
QFile file(outputFileName);
if (!file.open(QIODevice::WriteOnly)) {
qWarning() << "Couldn't open file for writing:" << outputFileName;
return;
}
file.write(jsonDoc.toJson());
file.close();
}
// 将QImage转换为Base64编码的字符串
QString MyGraphicsView::imageToBase64(const QImage& image)
{
QByteArray byteArray;
QBuffer buffer(&byteArray);
buffer.open(QIODevice::WriteOnly);
image.save(&buffer, "PNG"); // 使用PNG格式保存
return QString(byteArray.toBase64());
}
Json转Image
相反地,读取json文件,获取每个roi区域的x,y,width,height以及解码后的roi图像,利用painter对象将roi图像按原来的位置绘制。
void MyGraphicsView::on_btn_action_JsonToImage()
{
QFile file("./black.json");
if (!file.open(QIODevice::ReadOnly)) {
qWarning() << "Couldn't open file for reading:" ;
return;
}
// 创建一个QElapsedTimer对象
QElapsedTimer timer;
timer.start();
// 读取 JSON 文件并解析
QByteArray jsonData = file.readAll();
QJsonDocument jsonDoc = QJsonDocument::fromJson(jsonData);
QJsonObject root = jsonDoc.object();
// 创建一个与原图像大小相同的空白图像
QImage originalImage(4000, 4000, QImage::Format_RGB888);
originalImage.fill(Qt::white); // 背景颜色填充为白色(或者黑色)
// 获取所有 ROI
QJsonArray rois = root["ROIs"].toArray();
// 使用 QPainter 将每个 ROI 图像绘制到原始图像
QPainter painter(&originalImage);
for (const QJsonValue& value : rois) {
QJsonObject jsonRoi = value.toObject();
int x = jsonRoi["x"].toInt();
int y = jsonRoi["y"].toInt();
int w = jsonRoi["width"].toInt();
int h = jsonRoi["height"].toInt();
QString base64Image = jsonRoi["image"].toString();
// 将 Base64 编码还原为 QImage
QImage roiImage = base64ToImage(base64Image);
// 将 ROI 图像绘制到原图像的对应位置
painter.drawImage(QRect(x, y, w, h), roiImage);
}
painter.end();
// 计算经过的时间(毫秒)
qint64 elapsedTime = timer.elapsed();
qDebug() << "Json to Image time" << elapsedTime;
// 保存还原后的原图像
if (!originalImage.save("a.png"))
{
qWarning() << "Failed to save image";
}
else {
qDebug() << "Saved restored image";
}
}
// 将Base64字符串转换为QImage
QImage MyGraphicsView::base64ToImage(const QString& base64String)
{
QByteArray byteArray = QByteArray::fromBase64(base64String.toUtf8());
QImage image;
image.loadFromData(byteArray, "PNG");
return image;
}