// Media.cpp #include "Media.h" // YUV 转换为 RGB 的辅助函数 void yuvToRgb(int y, int u, int v, int& r, int& g, int& b) { r = y + 1.402 * (v - 128); g = y - 0.344136 * (u - 128) - 0.714136 * (v - 128); b = y + 1.772 * (u - 128); r = qBound(0, r, 255); g = qBound(0, g, 255); b = qBound(0, b, 255); } // 将 QImage 数据转换为 YUV422 QByteArray convertQImageToYUV422(const QImage& image) { int width = image.width(); int height = image.height(); QByteArray yuvData; yuvData.resize(width * height * 2); // YUV422: 每个像素2字节 int index = 0; for (int y = 0; y < height; ++y) { for (int x = 0; x < width; x += 2) { QRgb pixel0 = image.pixel(x, y); QRgb pixel1 = image.pixel(x + 1, y); int r0 = qRed(pixel0); int g0 = qGreen(pixel0); int b0 = qBlue(pixel0); int r1 = qRed(pixel1); int g1 = qGreen(pixel1); int b1 = qBlue(pixel1); // 计算YUV值 int y0 = (0.299 * r0 + 0.587 * g0 + 0.114 * b0); int u = (-0.169 * r0 - 0.331 * g0 + 0.5 * b0 + 128); int y1 = (0.299 * r1 + 0.587 * g1 + 0.114 * b1); int v = (0.5 * r0 - 0.419 * g0 - 0.081 * b0 + 128); yuvData[index++] = static_cast(qBound(0, y0, 255)); yuvData[index++] = static_cast(qBound(0, u, 255)); yuvData[index++] = static_cast(qBound(0, y1, 255)); yuvData[index++] = static_cast(qBound(0, v, 255)); } } return yuvData; } // 将 QImage 数据转换为 YUV420 QByteArray convertQImageToYUV420(const QImage& image) { int width = image.width(); int height = image.height(); QByteArray yuvData; int ySize = width * height; int uvSize = (width / 2) * (height / 2); yuvData.resize(ySize + 2 * uvSize); // Y 分量 + U 分量 + V 分量 int yIndex = 0; int uIndex = ySize; int vIndex = ySize + uvSize; for (int y = 0; y < height; y++) { for (int x = 0; x < width; x++) { QRgb pixel = image.pixel(x, y); int r = qRed(pixel); int g = qGreen(pixel); int b = qBlue(pixel); // 计算 YUV 值 int Y = qBound(0, static_cast(0.299 * r + 0.587 * g + 0.114 * b), 255); int U = qBound(0, static_cast(-0.169 * r - 0.331 * g + 0.5 * b + 128), 255); int V = qBound(0, static_cast(0.5 * r - 0.419 * g - 0.081 * b + 128), 255); // 填充 Y 分量 yuvData[yIndex++] = static_cast(Y); // 对 U 和 V 分量进行抽样 if (y % 2 == 0 && x % 2 == 0) { yuvData[uIndex++] = static_cast(U); yuvData[vIndex++] = static_cast(V); } } } return yuvData; } // 将 YUV422 数据转换为 QImage QImage convertYUV422ToQImage(const QByteArray& yuv422Data, int width, int height) { QImage image(width, height, QImage::Format_RGB888); const uchar* yuvPtr = reinterpret_cast(yuv422Data.constData()); const uchar* yuvDataEnd = yuvPtr + yuv422Data.size(); for (int y = 0; y < height; ++y) { for (int x = 0; x < width; x += 2) { if (yuvPtr + 4 > yuvDataEnd) { qWarning() << "YUV data access out of range!"; return image; } int y0 = yuvPtr[0]; int u = yuvPtr[1]; int y1 = yuvPtr[2]; int v = yuvPtr[3]; yuvPtr += 4; int r0, g0, b0; int r1, g1, b1; yuvToRgb(y0, u, v, r0, g0, b0); yuvToRgb(y1, u, v, r1, g1, b1); image.setPixel(x, y, qRgb(r0, g0, b0)); image.setPixel(x + 1, y, qRgb(r1, g1, b1)); } } return image; } // 将 YUV420 数据转换为 QImage QImage convertYUV420ToQImage(const QByteArray& yuv420Data, int width, int height) { QImage image(width, height, QImage::Format_RGB888); const uchar* yData = reinterpret_cast(yuv420Data.constData()); const uchar* uData = yData + width * height; const uchar* vData = uData + (width * height) / 4; for (int y = 0; y < height; ++y) { for (int x = 0; x < width; ++x) { int yValue = yData[y * width + x]; int uValue = uData[(y / 2) * (width / 2) + (x / 2)]; int vValue = vData[(y / 2) * (width / 2) + (x / 2)]; int r, g, b; yuvToRgb(yValue, uValue, vValue, r, g, b); image.setPixel(x, y, qRgb(r, g, b)); } } return image; } void DataHandler::showPic(QSize labelSize, int lens_n, int width, int height, int format, const QByteArray* valData) { qDebug() << "lens_n = " << lens_n; qDebug() << "format = " << format; qDebug() << "width = " << width; qDebug() << "height = " << height; qDebug() << "yuvData size = " << valData->size(); QImage image; if (format == YUV422) { image = convertYUV422ToQImage(*valData, width, height); } else if (format == YUV420) { image = convertYUV420ToQImage(*valData, width, height); } else { qWarning() << "Unsupported image format! Please use YUV422 or YUV420 format"; return; } QTransform transform; transform.rotate(90); // 可以调整旋转角度 QImage rotatedImage = image.transformed(transform); QImage scaledImage = rotatedImage.scaled(labelSize, Qt::KeepAspectRatio); QPixmap pixmap = QPixmap::fromImage(scaledImage); if (lens_n == 0) { //leftLens_m_imageLabel->setPixmap(QPixmap::fromImage(scaledImage)); emit updateLeftLensImage(pixmap); } else if (lens_n == 1) { //rightLens_m_imageLabel->setPixmap(QPixmap::fromImage(scaledImage)); emit updateRightLensImage(pixmap); } else { qWarning() << "Unsupported image lens!"; } // 生成保存图片的目录 QString saveDirPath = QDir::currentPath() + "/frontBoardImage"; QDir saveDir(saveDirPath); if (!saveDir.exists()) { saveDir.mkpath(saveDirPath); } QString currentTime = QDateTime::currentDateTime().toString("yyyyMMdd_HHmmss"); QByteArray rotatedYuvData; if (format == YUV422) { rotatedYuvData = convertQImageToYUV422(rotatedImage); } else if (format == YUV420) { rotatedYuvData = convertQImageToYUV420(rotatedImage); } QString yuvFileName = saveDirPath + "/" + currentTime + ".yuv"; QFile yuvFile(yuvFileName); if (yuvFile.open(QIODevice::WriteOnly)) { yuvFile.write(rotatedYuvData); yuvFile.close(); qDebug() << "YUV image saved to" << yuvFileName; } else { qWarning() << "Failed to save rotated YUV image to" << yuvFileName; } // 额外:可以保存旋转后的图像为JPG或PNG格式 QString rotatedImageFileName = saveDirPath + "/" + currentTime + ".jpg"; rotatedImage.save(rotatedImageFileName, "JPG"); qDebug() << "JPG image saved to" << rotatedImageFileName; } void SerialDataHandler::showPic(QSize labelSize, int lens_n, int width, int height, int format, const QByteArray* valData) { qDebug() << "lens_n = " << lens_n; qDebug() << "format = " << format; qDebug() << "width = " << width; qDebug() << "height = " << height; qDebug() << "yuvData size = " << valData->size(); QImage image; if (format == YUV422) { image = convertYUV422ToQImage(*valData, width, height); } else if (format == YUV420) { image = convertYUV420ToQImage(*valData, width, height); } else { qWarning() << "Unsupported image format! Please use YUV422 or YUV420 format"; return; } QTransform transform; transform.rotate(270); // 可以调整旋转角度 QImage rotatedImage = image.transformed(transform); QImage scaledImage = rotatedImage.scaled(labelSize, Qt::KeepAspectRatio); QPixmap pixmap = QPixmap::fromImage(scaledImage); if (lens_n == 0) { //leftLens_m_imageLabel->setPixmap(QPixmap::fromImage(scaledImage)); emit updateLeftLensImage(pixmap); } else if (lens_n == 1) { //rightLens_m_imageLabel->setPixmap(QPixmap::fromImage(scaledImage)); emit updateRightLensImage(pixmap); } else { qWarning() << "Unsupported image lens!"; } // 生成保存图片的目录 QString saveDirPath = QDir::currentPath() + "/frontBoardImage"; QDir saveDir(saveDirPath); if (!saveDir.exists()) { saveDir.mkpath(saveDirPath); } QString currentTime = QDateTime::currentDateTime().toString("yyyyMMdd_HHmmss"); QByteArray rotatedYuvData; if (format == YUV422) { rotatedYuvData = convertQImageToYUV422(rotatedImage); } else if (format == YUV420) { rotatedYuvData = convertQImageToYUV420(rotatedImage); } QString len_num = ""; if (lens_n == 0) len_num = "left"; else len_num = "right"; QString yuvFileName = saveDirPath + "/" + len_num + "_" + currentTime + ".yuv"; QFile yuvFile(yuvFileName); if (yuvFile.open(QIODevice::WriteOnly)) { yuvFile.write(rotatedYuvData); yuvFile.close(); qDebug() << "YUV image saved to" << yuvFileName; } else { qWarning() << "Failed to save rotated YUV image to" << yuvFileName; } // 额外:可以保存旋转后的图像为JPG或PNG格式 QString rotatedImageFileName = saveDirPath + "/" + len_num + "_" + currentTime + ".jpg"; rotatedImage.save(rotatedImageFileName, "JPG"); qDebug() << "JPG image saved to" << rotatedImageFileName; }