blob: 7084a68096223badf77d7bb795c338448c1d26fc [file] [log] [blame]
// Copyright 2020 Joe Drago. All rights reserved.
// SPDX-License-Identifier: BSD-2-Clause
#include "compare.h"
#include <math.h>
#include <stdlib.h>
#include <string.h>
avifBool compareYUVA(ImageComparison * ic, const avifImage * image1, const avifImage * image2)
{
memset(ic, 0, sizeof(ImageComparison));
if (!image1 || !image2) {
return AVIF_FALSE;
}
if ((image1->width != image2->width) || (image1->height != image2->height) || (image1->depth != image2->depth) ||
(image1->yuvFormat != image2->yuvFormat) || (image1->yuvRange != image2->yuvRange)) {
return AVIF_FALSE;
}
avifPixelFormatInfo formatInfo;
avifGetPixelFormatInfo(image1->yuvFormat, &formatInfo);
unsigned int uvW = image1->width >> formatInfo.chromaShiftX;
if (uvW < 1) {
uvW = 1;
}
unsigned int uvH = image1->height >> formatInfo.chromaShiftY;
if (uvH < 1) {
uvH = 1;
}
if (image1->depth == 8) {
// uint8_t path
uint8_t maxChannel = 255;
for (unsigned int j = 0; j < image1->height; ++j) {
for (unsigned int i = 0; i < image1->width; ++i) {
uint8_t * Y1 = &image1->yuvPlanes[AVIF_CHAN_Y][i + (j * image1->yuvRowBytes[AVIF_CHAN_Y])];
uint8_t * Y2 = &image2->yuvPlanes[AVIF_CHAN_Y][i + (j * image2->yuvRowBytes[AVIF_CHAN_Y])];
int diffY = abs(*Y1 - *Y2);
if (ic->maxDiffY < diffY) {
ic->maxDiffY = diffY;
}
ic->avgDiffY += (float)diffY;
uint8_t A1 = maxChannel;
if (image1->alphaPlane) {
A1 = image1->alphaPlane[i + (j * image1->alphaRowBytes)];
}
uint8_t A2 = maxChannel;
if (image2->alphaPlane) {
A2 = image2->alphaPlane[i + (j * image1->alphaRowBytes)];
}
int aDiff = abs(A1 - A2);
if (ic->maxDiffA < aDiff) {
ic->maxDiffA = aDiff;
}
ic->avgDiffA += (float)aDiff;
}
}
for (unsigned int j = 0; j < uvH; ++j) {
for (unsigned int i = 0; i < uvW; ++i) {
uint8_t * U1 = &image1->yuvPlanes[AVIF_CHAN_U][i + (j * image1->yuvRowBytes[AVIF_CHAN_U])];
uint8_t * U2 = &image2->yuvPlanes[AVIF_CHAN_U][i + (j * image2->yuvRowBytes[AVIF_CHAN_U])];
int diffU = abs(*U1 - *U2);
if (ic->maxDiffU < diffU) {
ic->maxDiffU = diffU;
}
ic->avgDiffU += (float)diffU;
uint8_t * V1 = &image1->yuvPlanes[AVIF_CHAN_V][i + (j * image1->yuvRowBytes[AVIF_CHAN_V])];
uint8_t * V2 = &image2->yuvPlanes[AVIF_CHAN_V][i + (j * image2->yuvRowBytes[AVIF_CHAN_V])];
int diffV = abs(*V1 - *V2);
if (ic->maxDiffV < diffV) {
ic->maxDiffV = diffV;
}
ic->avgDiffV += (float)diffV;
}
}
} else {
// uint16_t path
uint16_t maxChannel = (uint16_t)((1 << image1->depth) - 1);
for (unsigned int j = 0; j < image1->height; ++j) {
for (unsigned int i = 0; i < image1->width; ++i) {
uint16_t * Y1 =
(uint16_t *)&image1->yuvPlanes[AVIF_CHAN_Y][(i * sizeof(uint16_t)) + (j * image1->yuvRowBytes[AVIF_CHAN_Y])];
uint16_t * Y2 =
(uint16_t *)&image2->yuvPlanes[AVIF_CHAN_Y][(i * sizeof(uint16_t)) + (j * image2->yuvRowBytes[AVIF_CHAN_Y])];
int diffY = abs(*Y1 - *Y2);
if (ic->maxDiffY < diffY) {
ic->maxDiffY = diffY;
}
ic->avgDiffY += (float)diffY;
uint16_t A1 = maxChannel;
if (image1->alphaPlane) {
A1 = *((uint16_t *)&image1->alphaPlane[(i * sizeof(uint16_t)) + (j * image1->alphaRowBytes)]);
}
uint16_t A2 = maxChannel;
if (image2->alphaPlane) {
A2 = *((uint16_t *)&image2->alphaPlane[(i * sizeof(uint16_t)) + (j * image2->alphaRowBytes)]);
}
int aDiff = abs(A1 - A2);
if (ic->maxDiffA < aDiff) {
ic->maxDiffA = aDiff;
}
ic->avgDiffA += (float)aDiff;
}
}
for (unsigned int j = 0; j < uvH; ++j) {
for (unsigned int i = 0; i < uvW; ++i) {
uint16_t * U1 =
(uint16_t *)&image1->yuvPlanes[AVIF_CHAN_U][(i * sizeof(uint16_t)) + (j * image1->yuvRowBytes[AVIF_CHAN_U])];
uint16_t * U2 =
(uint16_t *)&image2->yuvPlanes[AVIF_CHAN_U][(i * sizeof(uint16_t)) + (j * image2->yuvRowBytes[AVIF_CHAN_U])];
int diffU = abs(*U1 - *U2);
if (ic->maxDiffU < diffU) {
ic->maxDiffU = diffU;
}
ic->avgDiffU += (float)diffU;
uint16_t * V1 =
(uint16_t *)&image1->yuvPlanes[AVIF_CHAN_V][(i * sizeof(uint16_t)) + (j * image1->yuvRowBytes[AVIF_CHAN_V])];
uint16_t * V2 =
(uint16_t *)&image2->yuvPlanes[AVIF_CHAN_V][(i * sizeof(uint16_t)) + (j * image2->yuvRowBytes[AVIF_CHAN_V])];
int diffV = abs(*V1 - *V2);
if (ic->maxDiffV < diffV) {
ic->maxDiffV = diffV;
}
ic->avgDiffV += (float)diffV;
}
}
}
float totalPixels = (float)(image1->width * image1->height);
ic->avgDiffY /= totalPixels;
ic->avgDiffU /= totalPixels;
ic->avgDiffV /= totalPixels;
ic->avgDiffA /= totalPixels;
ic->maxDiff = ic->maxDiffY;
if (ic->maxDiff < ic->maxDiffU) {
ic->maxDiff = ic->maxDiffU;
}
if (ic->maxDiff < ic->maxDiffV) {
ic->maxDiff = ic->maxDiffV;
}
if (ic->maxDiff < ic->maxDiffA) {
ic->maxDiff = ic->maxDiffA;
}
ic->avgDiff = (ic->avgDiffY + ic->avgDiffU + ic->avgDiffV + ic->avgDiffA) / 4.0f;
return AVIF_TRUE;
}