#include "../testTools.h" AlignedImageU8 addImages_generate(ImageU8 imageA, ImageU8 imageB) { int width = image_getWidth(imageA); int height = image_getHeight(imageA); // Call your lambda for width times height pixels return filter_generateU8(width, height, [imageA, imageB](int x, int y) { int lumaA = image_readPixel_clamp(imageA, x, y); int lumaB = image_readPixel_clamp(imageB, x, y); return lumaA + lumaB; } ); } void addImages_map(ImageU8 targetImage, ImageU8 imageA, ImageU8 imageB) { // Call your lambda for each pixel in targetImage filter_mapU8(targetImage, [imageA, imageB](int x, int y) { int lumaA = image_readPixel_clamp(imageA, x, y); int lumaB = image_readPixel_clamp(imageB, x, y); return lumaA + lumaB; } ); } void addImages_loop(ImageU8 targetImage, ImageU8 imageA, ImageU8 imageB) { int width = image_getWidth(targetImage); int height = image_getHeight(targetImage); // Loop over all x, y coordinates yourself for (int y = 0; y < height; y++) { for (int x = 0; x < width; x++) { int lumaA = image_readPixel_clamp(imageA, x, y); int lumaB = image_readPixel_clamp(imageB, x, y); image_writePixel(targetImage, x, y, lumaA + lumaB); } } } void addImages_pointer(ImageU8 targetImage, ImageU8 imageA, ImageU8 imageB) { int width = image_getWidth(targetImage); int height = image_getHeight(targetImage); SafePointer targetRow = image_getSafePointer(targetImage); SafePointer rowA = image_getSafePointer(imageA); SafePointer rowB = image_getSafePointer(imageB); int targetStride = image_getStride(targetImage); int strideA = image_getStride(imageA); int strideB = image_getStride(imageB); for (int y = 0; y < height; y++) { SafePointer targetPixel = targetRow; SafePointer pixelA = rowA; SafePointer pixelB = rowB; for (int x = 0; x < width; x++) { // Read both source pixels and add them int result = *pixelA + *pixelB; // Clamp overflow if (result > 255) result = 255; // Can skip underflow check //if (result < 0) result = 0; // Write the result *targetPixel = result; // Move pixel pointers to the next pixel targetPixel += 1; pixelA += 1; pixelB += 1; } // Move row pointers to the next row targetRow.increaseBytes(targetStride); rowA.increaseBytes(strideA); rowB.increaseBytes(strideB); } } void addImages_simd(AlignedImageU8 targetImage, AlignedImageU8 imageA, AlignedImageU8 imageB) { int width = image_getWidth(targetImage); int height = image_getHeight(targetImage); SafePointer targetRow = image_getSafePointer(targetImage); SafePointer rowA = image_getSafePointer(imageA); SafePointer rowB = image_getSafePointer(imageB); int targetStride = image_getStride(targetImage); int strideA = image_getStride(imageA); int strideB = image_getStride(imageB); for (int y = 0; y < height; y++) { SafePointer targetPixel = targetRow; SafePointer pixelA = rowA; SafePointer pixelB = rowB; // Assuming that we have ownership of any padding pixels for (int x = 0; x < width; x += 16) { // Read 16 source pixels at a time U8x16 a = U8x16::readAligned(pixelA, "addImages: reading pixelA"); U8x16 b = U8x16::readAligned(pixelB, "addImages: reading pixelB"); // Saturated operations replace conditional move U8x16 result = saturatedAddition(a, b); // Write the result 16 pixels at a time result.writeAligned(targetPixel, "addImages: writing result"); // Move pixel pointers to the next pixel targetPixel += 16; pixelA += 16; pixelB += 16; } // Move row pointers to the next row targetRow.increaseBytes(targetStride); rowA.increaseBytes(strideA); rowB.increaseBytes(strideB); } } // Making sure that all code examples from the image processing guide actually works START_TEST(Image) { AlignedImageU8 imageA = image_fromAscii( "< .x>" "< ... >" "< .xx. >" "< ..... >" "< .xx.. >" "< ..x.. >" "< ...... >" "< ..xx.. >" "< ..x. >" "< ..x.. >" "< ..x. >" "< ... >" "< ... >" "< ... >" "< .x.. >" ); AlignedImageU8 imageB = image_fromAscii( "< .x>" "< >" "< >" "< >" "<.. >" "<.xx... >" "<...xxxx.... >" "< ...xxxxxx...>" "< ....xxxxx>" "< ...x>" "< .>" "<.. >" "" "" "" ); // Using the generate method as a reference implementation. AlignedImageU8 imageExpected = addImages_generate(imageA, imageB); //printText("\nGenerate result:\n", image_toAscii(imageExpected)); AlignedImageU8 imageResult = image_create_U8(15, 14); addImages_map(imageResult, imageA, imageB); //printText("\nMap result:\n", image_toAscii(imageResult)); ASSERT_EQUAL(image_maxDifference(imageResult, imageExpected), 0); addImages_loop(imageResult, imageA, imageB); //printText("\nLoop result:\n", image_toAscii(imageResult)); ASSERT_EQUAL(image_maxDifference(imageResult, imageExpected), 0); addImages_pointer(imageResult, imageA, imageB); //printText("\nPointer result:\n", image_toAscii(imageResult)); ASSERT_EQUAL(image_maxDifference(imageResult, imageExpected), 0); addImages_simd(imageResult, imageA, imageB); //printText("\nSIMD result:\n", image_toAscii(imageResult)); ASSERT_EQUAL(image_maxDifference(imageResult, imageExpected), 0); } END_TEST