Skip to content

Commit 2f03761

Browse files
committed
fix: correct YUV420 to RGB conversion for Raspberry Pi camera output
1 parent 5600230 commit 2f03761

1 file changed

Lines changed: 22 additions & 12 deletions

File tree

src/libcameracamera.cpp

Lines changed: 22 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -540,33 +540,43 @@ QImage LibCameraWorker::convertBufferToImage(
540540
}
541541
}
542542
} else if (cfg.pixelFormat == libcamera::formats::YUV420) {
543-
// YUV420 planar format (I420)
543+
// YUV420 planar format - Pi camera uses I420 (Y, U, V order)
544+
// But colors appear swapped, so this might be YV12 (Y, V, U order)
544545
unsigned int width = cfg.size.width;
545546
unsigned int height = cfg.size.height;
547+
unsigned int stride = cfg.stride;
546548
image = QImage(width, height, QImage::Format_RGB888);
547549

548550
const uint8_t *src = static_cast<const uint8_t *>(memory);
549551
const uint8_t *yPlane = src;
550-
const uint8_t *uPlane = src + width * height;
551-
const uint8_t *vPlane = uPlane + (width * height / 4);
552+
// Swap U and V planes - Pi outputs Y, V, U (YV12) not Y, U, V (I420)
553+
const uint8_t *vPlane = src + stride * height;
554+
const uint8_t *uPlane = vPlane + (stride / 2) * (height / 2);
552555

553556
for (unsigned int y = 0; y < height; y++) {
557+
uint8_t *destRow = image.scanLine(y);
554558
for (unsigned int x = 0; x < width; x++) {
555-
int yVal = yPlane[y * width + x];
556-
int uVal = uPlane[(y / 2) * (width / 2) + (x / 2)];
557-
int vVal = vPlane[(y / 2) * (width / 2) + (x / 2)];
558-
559-
auto clamp = [](int val) { return std::max(0, std::min(255, val)); };
559+
int yVal = yPlane[y * stride + x];
560+
int uVal = uPlane[(y / 2) * (stride / 2) + (x / 2)];
561+
int vVal = vPlane[(y / 2) * (stride / 2) + (x / 2)];
560562

563+
// YUV to RGB conversion
561564
int c = yVal - 16;
562565
int d = uVal - 128;
563566
int e = vVal - 128;
564567

565-
int r = clamp((298 * c + 409 * e + 128) >> 8);
566-
int g = clamp((298 * c - 100 * d - 208 * e + 128) >> 8);
567-
int b = clamp((298 * c + 516 * d + 128) >> 8);
568+
int r = (298 * c + 409 * e + 128) >> 8;
569+
int g = (298 * c - 100 * d - 208 * e + 128) >> 8;
570+
int b = (298 * c + 516 * d + 128) >> 8;
571+
572+
// Clamp values
573+
r = r < 0 ? 0 : (r > 255 ? 255 : r);
574+
g = g < 0 ? 0 : (g > 255 ? 255 : g);
575+
b = b < 0 ? 0 : (b > 255 ? 255 : b);
568576

569-
image.setPixel(x, y, qRgb(r, g, b));
577+
destRow[x * 3 + 0] = static_cast<uint8_t>(r);
578+
destRow[x * 3 + 1] = static_cast<uint8_t>(g);
579+
destRow[x * 3 + 2] = static_cast<uint8_t>(b);
570580
}
571581
}
572582
} else {

0 commit comments

Comments
 (0)