diff --git a/Frameworks/Accelerate/vDSP.cpp b/Frameworks/Accelerate/vDSP.cpp index 02641c494d..6290892951 100644 --- a/Frameworks/Accelerate/vDSP.cpp +++ b/Frameworks/Accelerate/vDSP.cpp @@ -810,8 +810,7 @@ void vDSP_measqv(const float *A, vDSP_Stride IA, float *C, vDSP_Length N) { } *C = c; - } - else { + } else { *C = FP_NAN; } } @@ -828,8 +827,7 @@ void vDSP_measqvD(const double *A, vDSP_Stride IA, double *C, vDSP_Length N) { } *C = c; - } - else { + } else { *C = FP_NAN; } } @@ -855,8 +853,7 @@ void vDSP_rmsqv(const float *A, vDSP_Stride IA, float *C, vDSP_Length N) { c = sqrt(c) * max; } *C = c; - } - else { + } else { *C = FP_NAN; } } @@ -883,8 +880,7 @@ void vDSP_rmsqvD(const double *A, vDSP_Stride IA, double *C, vDSP_Length N) { c = sqrt(c) * max; } *C = c; - } - else { + } else { *C = FP_NAN; } } @@ -922,3 +918,303 @@ void vDSP_blkman_windowD(double *C, vDSP_Length N, int Flag) { } } + +static inline int isPowerOfTwo(vDSP_Length length) { + return !(length & (length - 1)); +} + + +static inline int isValidDFTLength(vDSP_Length length, unsigned int minLength) { + return isPowerOfTwo(length) || + ((length % 3 == 0) && isPowerOfTwo(length / 3) && (length >= 3 * minLength)) || + ((length % 5 == 0) && isPowerOfTwo(length / 5) && (length >= 5 * minLength)) || + ((length % 15 == 0) && isPowerOfTwo(length / 15) && (length >= 15 * minLength)); +} + + +//Creates a setup object to be used for complex-to-complex single-precision DFT/IDFT computation +vDSP_DFT_Setup vDSP_DFT_zop_CreateSetup(vDSP_DFT_Setup __Previous, vDSP_Length __Length, vDSP_DFT_Direction __Direction) { + vDSP_DFT_Setup DFTObject; + if (!__Previous) { + DFTObject = new vDSP_DFT_SetupStruct; + } else { + DFTObject = __Previous; + } + + if (!DFTObject || __Length <= 0 || (__Direction != vDSP_DFT_FORWARD && __Direction != vDSP_DFT_INVERSE)) { + return nullptr; + } + + //Check for length requirements - Power of Two (or) Power of Two multiplied by 3, 5, or 15 + if (!isValidDFTLength(__Length, 8)) { + return nullptr; + } + + DFTObject->transformLength = __Length; + DFTObject->transformDirection = __Direction; + DFTObject->transformType = ZOP; + return DFTObject; +} + + +//Creates a setup object to be used for complex-to-complex double-precision DFT/IDFT computation +vDSP_DFT_SetupD vDSP_DFT_zop_CreateSetupD(vDSP_DFT_SetupD __Previous, vDSP_Length __Length, vDSP_DFT_Direction __Direction) { + vDSP_DFT_SetupD DFTDObject; + if (!__Previous) { + DFTDObject = new vDSP_DFT_SetupStructD; + } else { + DFTDObject = __Previous; + } + + if (!DFTDObject || __Length <= 0 || (__Direction != vDSP_DFT_FORWARD && __Direction != vDSP_DFT_INVERSE)) { + return nullptr; + } + + //Check for length requirements - Power of Two (or) Power of Two multiplied by 3, 5, or 15 + if (!isValidDFTLength(__Length, 8)) { + return nullptr; + } + + DFTDObject->transformLength = __Length; + DFTDObject->transformDirection = __Direction; + DFTDObject->transformType = ZOP; + return DFTDObject; +} + + +//Creates a setup object to be used for real-to-complex (complex-to-real) single-precision DFT (IDFT) computation +vDSP_DFT_Setup vDSP_DFT_zrop_CreateSetup(vDSP_DFT_Setup __Previous, vDSP_Length __Length, vDSP_DFT_Direction __Direction) { + vDSP_DFT_Setup DFTObject; + if (!__Previous) { + DFTObject = new vDSP_DFT_SetupStruct; + } else { + DFTObject = __Previous; + } + + if (!DFTObject || __Length <= 0 || (__Direction != vDSP_DFT_FORWARD && __Direction != vDSP_DFT_INVERSE)) { + return nullptr; + } + + //Check for length requirements - Power of Two (or) Power of Two multiplied by 3, 5, or 15 + if (!isValidDFTLength(__Length, 16)) { + return nullptr; + } + + DFTObject->transformLength = __Length; + DFTObject->transformDirection = __Direction; + DFTObject->transformType = ZROP; + return DFTObject; +} + + +//Creates a setup object to be used for real-to-complex (complex-to-real) double-precision DFT (IDFT) computation +vDSP_DFT_SetupD vDSP_DFT_zrop_CreateSetupD(vDSP_DFT_SetupD __Previous, vDSP_Length __Length, vDSP_DFT_Direction __Direction) { + vDSP_DFT_SetupD DFTDObject; + if (!__Previous) { + DFTDObject = new vDSP_DFT_SetupStructD; + } else { + DFTDObject = __Previous; + } + + if (!DFTDObject || __Length <= 0 || (__Direction != vDSP_DFT_FORWARD && __Direction != vDSP_DFT_INVERSE)) { + return nullptr; + } + + //Check for length requirements - Power of Two (or) Power of Two multiplied by 3, 5, or 15 + if (!isValidDFTLength(__Length, 16)) { + return nullptr; + } + + DFTDObject->transformLength = __Length; + DFTDObject->transformDirection = __Direction; + DFTDObject->transformType = ZROP; + return DFTDObject; +} + + +//Computes the single-precision DFT for a vector +void vDSP_DFT_Execute(const struct vDSP_DFT_SetupStruct *__Setup, const float *__Ir, const float *__Ii, float *__Or, float *__Oi) { + if (!__Setup) { + return; + } + + int length = __Setup->transformLength; + int direction = __Setup->transformDirection; + float scale; + float kscale; + float real; + float imaginary; + + if (__Setup->transformType == ZOP) { + scale = 2 * static_cast(M_PI) * direction / length; + for (int k = 0; k < length; k++) { + real = 0; + imaginary = 0; + kscale = k * scale; + for (int n = 0; n < length; n++) { + real += (__Ir[n] * cos(n * kscale)) + (__Ii[n] * sin(n * kscale)); + imaginary += (__Ii[n] * cos(n * kscale)) - (__Ir[n] * sin(n * kscale)); + } + + __Or[k] = real; + __Oi[k] = imaginary; + } + } else if (__Setup->transformType == ZROP) { + if (direction == vDSP_DFT_FORWARD) { + float* realInput = new float[length]; + for (int i = 0; i < length / 2; i++) { + realInput[2 * i + 0] = __Ir[i]; + realInput[2 * i + 1] = __Ii[i]; + } + + scale = 2 * static_cast(M_PI) / length; + for (int k = 0; k < length / 2; k++) { + real = 0; + imaginary = 0; + kscale = k * scale; + for (int n = 0; n < length; n++) { + real += realInput[n] * cos(n * kscale); + + //Block added to match Apple's special case for the first imaginary output + if (k == 0) { + imaginary += realInput[n] * cos(static_cast(M_PI) * n); + } else { + imaginary -= realInput[n] * sin(n * kscale); + } + } + + __Or[k] = real * 2; + __Oi[k] = imaginary * 2; + } + + delete realInput; + } else if (direction == vDSP_DFT_INVERSE) { + float* realOutput = new float[length]; + scale = 2 * static_cast(M_PI) / length; + for (int k = 0; k < length; k++) { + real = 0; + kscale = k * scale; + for (int n = 0; n < length; n++) { + real += (__Ir[n] * cos(n * kscale)) - (__Ii[n] * sin(n * kscale)); + } + + realOutput[k] = real; + } + + for (int i = 0; i < length / 2; i++) { + __Or[i] = realOutput[2 * i + 0]; + __Oi[i] = realOutput[2 * i + 1]; + + //Block added to match iOS behavior + __Or[i] -= __Ir[length / 2]; + __Oi[i] += __Ir[length / 2]; + } + + delete realOutput; + } + } +} + + +//Computes the double-precision DFT for a vector +void vDSP_DFT_ExecuteD(const struct vDSP_DFT_SetupStructD *__Setup, const double *__Ir, const double *__Ii, double *__Or, double *__Oi) { + if (!__Setup) { + return; + } + + int length = __Setup->transformLength; + int direction = __Setup->transformDirection; + double scale; + double kscale; + double real; + double imaginary; + + if (__Setup->transformType == ZOP) { + scale = 2 * M_PI * direction / length; + for (int k = 0; k < length; k++) { + real = 0; + imaginary = 0; + kscale = k * scale; + for (int n = 0; n < length; n++) { + real += (__Ir[n] * cos(n * kscale)) + (__Ii[n] * sin(n * kscale)); + imaginary += (__Ii[n] * cos(n * kscale)) - (__Ir[n] * sin(n * kscale)); + } + + __Or[k] = real; + __Oi[k] = imaginary; + } + } else if (__Setup->transformType == ZROP) { + if (direction == vDSP_DFT_FORWARD) { + double* realInput = new double[length]; + for (int i = 0; i < length / 2; i++) { + realInput[2 * i + 0] = __Ir[i]; + realInput[2 * i + 1] = __Ii[i]; + } + + scale = 2 * M_PI / length; + for (int k = 0; k < length / 2; k++) { + real = 0; + imaginary = 0; + kscale = k * scale; + for (int n = 0; n < length; n++) { + real += realInput[n] * cos(n * kscale); + + //Block added to match Apple's special case for the first imaginary output + if (k == 0) { + imaginary += realInput[n] * cos(M_PI * n); + } else { + imaginary -= realInput[n] * sin(n * kscale); + } + } + + __Or[k] = real * 2; + __Oi[k] = imaginary * 2; + } + + delete realInput; + } else if (direction == vDSP_DFT_INVERSE) { + double* realOutput = new double[length]; + scale = 2 * M_PI / length; + for (int k = 0; k < length; k++) { + real = 0; + kscale = k * scale; + for (int n = 0; n < length; n++) { + real += (__Ir[n] * cos(n * kscale)) - (__Ii[n] * sin(n * kscale)); + } + + realOutput[k] = real; + } + + for (int i = 0; i < length / 2; i++) { + __Or[i] = realOutput[2 * i + 0]; + __Oi[i] = realOutput[2 * i + 1]; + + //Block added to match iOS behavior + __Or[i] -= __Ir[length / 2]; + __Oi[i] += __Ir[length / 2]; + } + + delete realOutput; + } + } +} + + +//Releases a single-precision setup object +void vDSP_DFT_DestroySetup(vDSP_DFT_Setup __Setup) { + if (__Setup) { + delete __Setup; + } + + return; +} + + +//Releases a double-precision setup object +void vDSP_DFT_DestroySetupD(vDSP_DFT_SetupD __Setup) { + if (__Setup) { + delete __Setup; + } + + return; +} \ No newline at end of file diff --git a/Frameworks/Accelerate/vImage.cpp b/Frameworks/Accelerate/vImage.cpp new file mode 100644 index 0000000000..7715ce3e51 --- /dev/null +++ b/Frameworks/Accelerate/vImage.cpp @@ -0,0 +1,954 @@ +//****************************************************************************** +// +// Copyright (c) 2016, Intel Corporation +// Copyright (c) 2015 Microsoft Corporation. All rights reserved. +// +// This code is licensed under the MIT License (MIT). +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +// +//****************************************************************************** + +#include +#include "Accelerate\vImage.h" + +/** +@Status Interoperable +*/ + +vImage_Error vImageBoxConvolve_ARGB8888(const vImage_Buffer* src, + const vImage_Buffer* dest, + void* tempBuffer, + vImagePixelCount srcOffsetToROI_X, + vImagePixelCount srcOffsetToROI_Y, + uint32_t kernel_height, + uint32_t kernel_width, + const Pixel_8888 backgroundColor, + vImage_Flags flags) { + if (src == nullptr || dest == nullptr || src->data == nullptr || dest->data == nullptr) { + return kvImageNullPointerArgument; + } else if (!(kernel_height & kernel_width & 1)) { + return kvImageInvalidKernelSize; + } else if (srcOffsetToROI_X > src->width) { + return kvImageInvalidOffset_X; + } else if (srcOffsetToROI_Y > src->height) { + return kvImageInvalidOffset_Y; + } else if ((srcOffsetToROI_Y + dest->height > src->height) || (srcOffsetToROI_X + dest->width > src->width)) { + return kvImageRoiLargerThanInputBuffer; + } else if (!(flags & kvImageCopyInPlace) && !(flags & kvImageBackgroundColorFill) && + !(flags & kvImageEdgeExtend) && !(flags & kvImageTruncateKernel)) { + return kvImageInvalidEdgeStyle; + } + + const unsigned long maxVal = 2147483647; + + // Caveat: We return kvImageInvalidParameter for height, width, srcOffsetToROI_X, and srcOffsetToROI_Y >=2^31 + // For 32 bit OS, we don't expect size >= 2^31. Hence it is not supported in current release. + // TODO for 64-bit + if (src->height > maxVal || src->width > maxVal || dest->height > maxVal || dest->width > maxVal + || srcOffsetToROI_X > maxVal || srcOffsetToROI_Y > maxVal || kernel_height> maxVal || kernel_width > maxVal) { + return kvImageInvalidParameter; + } + + int KW_d2 = kernel_width / 2; + int KH_d2 = kernel_height / 2; + + // The following 4 variable denote the location of the first and last pixel to have the kernel + // completely overlapping with source image + uint32_t start_i = 0; + uint32_t start_j = 0; + uint32_t end_i = dest->height - 1; + uint32_t end_j = dest->width - 1; + + if (srcOffsetToROI_Y < KH_d2) { + start_i = KH_d2 - srcOffsetToROI_Y; + } + + if (srcOffsetToROI_X < KW_d2) { + start_j = KW_d2 - srcOffsetToROI_X; + } + + if (src->height < (srcOffsetToROI_Y + dest->height + KH_d2)) { + end_i = src->height - srcOffsetToROI_Y - KH_d2 - 1; + } + + if (src->width < (srcOffsetToROI_X + dest->width + KW_d2)) { + end_j = src->width - srcOffsetToROI_X - KW_d2 - 1; + } + + // The following two variable denote the no of rows required for temporary storage for first pass + // above and below the RoI + int top = KH_d2 - start_i; + int below = end_i + 1 + KH_d2 - dest->height; + + // returns the size of temporary buffer data + if (flags & kvImageGetTempBufferSize) { + return (dest->height + (top + below) * dest->width) * sizeof(Pixel_8888_s); + } + + // Pointer to access the temporary buffer data. + Pixel_8888_s* temp_buf; + bool tempBuffer_flag = 0; + if (tempBuffer == nullptr) { + temp_buf = new(std::nothrow) Pixel_8888_s[(dest->height + (top + below) * dest->width)]; + if (temp_buf == nullptr) { + return kvImageMemoryAllocationError; + } + tempBuffer_flag = 1; + } else { + temp_buf = static_cast(tempBuffer); + } + + uint32_t sum[4] = { 0 }; + uint32_t src_i; + uint32_t src_j; + Pixel_8888_s* src_buf = static_cast(src->data); + Pixel_8888_s* dest_buf = static_cast(dest->data); + size_t src_rowstride = src->rowBytes / sizeof(Pixel_8888); + size_t dest_rowstride = dest->rowBytes / sizeof(Pixel_8888); + + // This block deals with code for flag kvImageCopyInPlace, which require the pixel to be copied as is + // from source image when the kernel does not overlap with the image data + if (flags & kvImageCopyInPlace) { + bool sum_flag = 0; + + // First pass (horizontal) + for (uint32_t i = 0; i < dest->height; ++i) { + src_i = srcOffsetToROI_Y + i; + src_j = srcOffsetToROI_X; + sum_flag = 0; + sum[0] = 0; + sum[1] = 0; + sum[2] = 0; + sum[3] = 0; + + for (uint32_t j = 0; j < dest->width; ++j, src_j++) { + + // Copying the pixel data as is from source for no kernel overlap section + if (j < start_j || j > end_j) { + dest_buf[i * dest_rowstride + j] = src_buf[src_i * src_rowstride + src_j]; + } else { + if (sum_flag == 0) { + sum_flag = 1; + for (int k = -KW_d2; k <= KW_d2; ++k) { + sum[0] += src_buf[src_i * src_rowstride + src_j + k].val[0]; + sum[1] += src_buf[src_i * src_rowstride + src_j + k].val[1]; + sum[2] += src_buf[src_i * src_rowstride + src_j + k].val[2]; + sum[3] += src_buf[src_i * src_rowstride + src_j + k].val[3]; + } + } else { + sum[0] += -src_buf[src_i * src_rowstride + src_j - KW_d2 - 1].val[0] + + src_buf[src_i * src_rowstride + src_j + KW_d2].val[0]; + sum[1] += -src_buf[src_i * src_rowstride + src_j - KW_d2 - 1].val[1] + + src_buf[src_i * src_rowstride + src_j + KW_d2].val[1]; + sum[2] += -src_buf[src_i * src_rowstride + src_j - KW_d2 - 1].val[2] + + src_buf[src_i * src_rowstride + src_j + KW_d2].val[2]; + sum[3] += -src_buf[src_i * src_rowstride + src_j - KW_d2 - 1].val[3] + + src_buf[src_i * src_rowstride + src_j + KW_d2].val[3]; + } + + dest_buf[i * dest_rowstride + j].val[0] = sum[0] > (255 * kernel_width) ? 255 : sum[0] / kernel_width; + dest_buf[i * dest_rowstride + j].val[1] = sum[1] > (255 * kernel_width) ? 255 : sum[1] / kernel_width; + dest_buf[i * dest_rowstride + j].val[2] = sum[2] > (255 * kernel_width) ? 255 : sum[2] / kernel_width; + dest_buf[i * dest_rowstride + j].val[3] = sum[3] > (255 * kernel_width) ? 255 : sum[3] / kernel_width; + } + } + } + + // first pass above("top") the RoI + for (int i = start_i - KH_d2; i < 0; ++i) { + src_i = srcOffsetToROI_Y + i; + src_j = srcOffsetToROI_X; + sum_flag = 0; + sum[0] = 0; + sum[1] = 0; + sum[2] = 0; + sum[3] = 0; + + for (uint32_t j = 0; j < dest->width; ++j, src_j++) { + + // Copying the pixel data as is from source for no kernel overlap section + if (j < start_j || j > end_j) { + temp_buf[(top + i)*dest_rowstride] = src_buf[src_i * src_rowstride + src_j]; + } else { + if (sum_flag == 0) { + sum_flag = 1; + for (int k = -KW_d2; k <= KW_d2; ++k) { + sum[0] += src_buf[src_i * src_rowstride + src_j + k].val[0]; + sum[1] += src_buf[src_i * src_rowstride + src_j + k].val[1]; + sum[2] += src_buf[src_i * src_rowstride + src_j + k].val[2]; + sum[3] += src_buf[src_i * src_rowstride + src_j + k].val[3]; + } + } else { + sum[0] = sum[0] - src_buf[src_i * src_rowstride + src_j - KW_d2 - 1].val[0] + + src_buf[src_i * src_rowstride + src_j + KW_d2].val[0]; + sum[1] = sum[1] - src_buf[src_i * src_rowstride + src_j - KW_d2 - 1].val[1] + + src_buf[src_i * src_rowstride + src_j + KW_d2].val[1]; + sum[2] = sum[2] - src_buf[src_i * src_rowstride + src_j - KW_d2 - 1].val[2] + + src_buf[src_i * src_rowstride + src_j + KW_d2].val[2]; + sum[3] = sum[3] - src_buf[src_i * src_rowstride + src_j - KW_d2 - 1].val[3] + + src_buf[src_i * src_rowstride + src_j + KW_d2].val[3]; + } + + temp_buf[(top + i) * dest_rowstride + j].val[0] = sum[0] > (255 * kernel_width) ? 255 : sum[0] / kernel_width; + temp_buf[(top + i) * dest_rowstride + j].val[1] = sum[1] > (255 * kernel_width) ? 255 : sum[1] / kernel_width; + temp_buf[(top + i) * dest_rowstride + j].val[2] = sum[2] > (255 * kernel_width) ? 255 : sum[2] / kernel_width; + temp_buf[(top + i) * dest_rowstride + j].val[3] = sum[3] > (255 * kernel_width) ? 255 : sum[3] / kernel_width; + } + } + } + + // first pass below the RoI + for (uint32_t i = dest->height; i <= end_i + KH_d2; ++i) { + src_i = srcOffsetToROI_Y + i; + src_j = srcOffsetToROI_X; + sum_flag = 0; + sum[0] = 0; + sum[1] = 0; + sum[2] = 0; + sum[3] = 0; + + for (uint32_t j = 0; j < dest->width; ++j, src_j++) { + + // Copying the pixel data as is from source for no kernel overlap section + if (j < start_j || j > end_j) { + temp_buf[(top + (i - dest->height)) * dest_rowstride + j] = src_buf[src_i * src_rowstride + src_j]; + } else { + if (sum_flag == 0) { + sum_flag = 1; + for (int k = -KW_d2; k <= KW_d2; ++k) { + sum[0] += src_buf[src_i * src_rowstride + src_j + k].val[0]; + sum[1] += src_buf[src_i * src_rowstride + src_j + k].val[1]; + sum[2] += src_buf[src_i * src_rowstride + src_j + k].val[2]; + sum[3] += src_buf[src_i * src_rowstride + src_j + k].val[3]; + } + } else { + sum[0] = sum[0] - src_buf[src_i * src_rowstride + src_j - KW_d2 - 1].val[0] + + src_buf[src_i * src_rowstride + src_j + KW_d2].val[0]; + sum[1] = sum[1] - src_buf[src_i * src_rowstride + src_j - KW_d2 - 1].val[1] + + src_buf[src_i * src_rowstride + src_j + KW_d2].val[1]; + sum[2] = sum[2] - src_buf[src_i * src_rowstride + src_j - KW_d2 - 1].val[2] + + src_buf[src_i * src_rowstride + src_j + KW_d2].val[2]; + sum[3] = sum[3] - src_buf[src_i * src_rowstride + src_j - KW_d2 - 1].val[3] + + src_buf[src_i * src_rowstride + src_j + KW_d2].val[3]; + } + + temp_buf[(top + (i - dest->height)) * dest_rowstride + j].val[0] + = sum[0] > (255 * kernel_width) ? 255 : sum[0] / kernel_width; + temp_buf[(top + (i - dest->height)) * dest_rowstride + j].val[1] + = sum[1] > (255 * kernel_width) ? 255 : sum[1] / kernel_width; + temp_buf[(top + (i - dest->height)) * dest_rowstride + j].val[2] + = sum[2] > (255 * kernel_width) ? 255 : sum[2] / kernel_width; + temp_buf[(top + (i - dest->height)) * dest_rowstride + j].val[3] + = sum[3] > (255 * kernel_width) ? 255 : sum[3] / kernel_width; + } + } + } + + // Second pass (vertical) + for (uint32_t j = start_j; j <= end_j; ++j) { + sum_flag = 0; + sum[0] = 0; + sum[1] = 0; + sum[2] = 0; + sum[3] = 0; + + for (int i = start_i; i <= static_cast(end_i); ++i) { + if (sum_flag == 0) { + sum_flag = 1; + for (int k = -KH_d2; k <= KH_d2; ++k) { + if (i + k < 0) { + sum[0] += temp_buf[(top + (i + k)) * dest_rowstride + j].val[0]; + sum[1] += temp_buf[(top + (i + k)) * dest_rowstride + j].val[1]; + sum[2] += temp_buf[(top + (i + k)) * dest_rowstride + j].val[2]; + sum[3] += temp_buf[(top + (i + k)) * dest_rowstride + j].val[3]; + } else { + sum[0] += dest_buf[(i + k) * dest_rowstride + j].val[0]; + sum[1] += dest_buf[(i + k) * dest_rowstride + j].val[1]; + sum[2] += dest_buf[(i + k) * dest_rowstride + j].val[2]; + sum[3] += dest_buf[(i + k) * dest_rowstride + j].val[3]; + } + } + } else { + if (i - KH_d2 - 1 < 0) { + sum[0] -= temp_buf[(top + (i - KH_d2 - 1)) * dest_rowstride + j].val[0]; + sum[1] -= temp_buf[(top + (i - KH_d2 - 1)) * dest_rowstride + j].val[1]; + sum[2] -= temp_buf[(top + (i - KH_d2 - 1)) * dest_rowstride + j].val[2]; + sum[3] -= temp_buf[(top + (i - KH_d2 - 1)) * dest_rowstride + j].val[3]; + } else { + sum[0] -= dest_buf[(i - KH_d2 - 1) * dest_rowstride + j].val[0]; + sum[1] -= dest_buf[(i - KH_d2 - 1) * dest_rowstride + j].val[1]; + sum[2] -= dest_buf[(i - KH_d2 - 1) * dest_rowstride + j].val[2]; + sum[3] -= dest_buf[(i - KH_d2 - 1) * dest_rowstride + j].val[3]; + } + + if (i + KH_d2 >= static_cast(dest->height)) { + sum[0] += temp_buf[(top + (i + KH_d2) - dest->height) * dest_rowstride + j].val[0]; + sum[1] += temp_buf[(top + (i + KH_d2) - dest->height) * dest_rowstride + j].val[1]; + sum[2] += temp_buf[(top + (i + KH_d2) - dest->height) * dest_rowstride + j].val[2]; + sum[3] += temp_buf[(top + (i + KH_d2) - dest->height) * dest_rowstride + j].val[3]; + } else { + sum[0] += dest_buf[(i + KH_d2) * dest_rowstride + j].val[0]; + sum[1] += dest_buf[(i + KH_d2) * dest_rowstride + j].val[1]; + sum[2] += dest_buf[(i + KH_d2) * dest_rowstride + j].val[2]; + sum[3] += dest_buf[(i + KH_d2) * dest_rowstride + j].val[3]; + } + } + + temp_buf[(top + below) * dest_rowstride + i - start_i].val[0] + = sum[0] > (255 * kernel_height) ? 255 : sum[0] / kernel_height; + temp_buf[(top + below) * dest_rowstride + i - start_i].val[1] + = sum[1] > (255 * kernel_height) ? 255 : sum[1] / kernel_height; + temp_buf[(top + below) * dest_rowstride + i - start_i].val[2] + = sum[2] > (255 * kernel_height) ? 255 : sum[2] / kernel_height; + temp_buf[(top + below) * dest_rowstride + i - start_i].val[3] + = sum[3] > (255 * kernel_height) ? 255 : sum[3] / kernel_height; + } + + for (uint32_t i = start_i; i <= end_i; ++i) { + dest_buf[i * dest_rowstride + j] = temp_buf[(top + below) * dest_rowstride + i - start_i]; + } + } + + for (uint32_t i = 0; i < start_i; ++i) { + src_i = srcOffsetToROI_Y + i; + src_j = srcOffsetToROI_X + start_j; + for (uint32_t j = start_j; j <= end_j; ++j, src_j++) { + dest_buf[i * dest_rowstride + j] = src_buf[src_i * src_rowstride + src_j]; + } + } + + for (uint32_t i = end_i + 1; i < dest->height; ++i) { + src_i = srcOffsetToROI_Y + i; + src_j = srcOffsetToROI_X + start_j; + for (uint32_t j = start_j; j <= end_j; ++j, src_j++) { + dest_buf[i * dest_rowstride + j] = src_buf[src_i * src_rowstride + src_j]; + } + } + } + + // This block deals with code for flag kvImageTruncateKernel, which require the kernel to be truncated + // when it does not overlap with the image data + else if (flags & kvImageTruncateKernel) { + uint32_t divisor; + + // First pass (horizontal) + for (int i = static_cast(start_i) - KH_d2; i <= static_cast(end_i) + KH_d2; ++i) { + src_i = srcOffsetToROI_Y + i; + src_j = srcOffsetToROI_X; + sum[0] = 0; + sum[1] = 0; + sum[2] = 0; + sum[3] = 0; + divisor = kernel_width - start_j; + + for (int k = start_j - KW_d2; k <= KW_d2; ++k) { + sum[0] += src_buf[src_i * src_rowstride + src_j + k].val[0]; + sum[1] += src_buf[src_i * src_rowstride + src_j + k].val[1]; + sum[2] += src_buf[src_i * src_rowstride + src_j + k].val[2]; + sum[3] += src_buf[src_i * src_rowstride + src_j + k].val[3]; + } + + if (i<0) { + temp_buf[(top + i) * dest_rowstride].val[0] = sum[0] > (255 * divisor) ? 255 : sum[0] / divisor; + temp_buf[(top + i) * dest_rowstride].val[1] = sum[1] > (255 * divisor) ? 255 : sum[1] / divisor; + temp_buf[(top + i) * dest_rowstride].val[2] = sum[2] > (255 * divisor) ? 255 : sum[2] / divisor; + temp_buf[(top + i) * dest_rowstride].val[3] = sum[3] > (255 * divisor) ? 255 : sum[3] / divisor; + } else if (i >= static_cast(dest->height)) { + temp_buf[(top + (i - dest->height)) * dest_rowstride].val[0] = sum[0] > (255 * divisor) ? 255 : sum[0] / divisor; + temp_buf[(top + (i - dest->height)) * dest_rowstride].val[1] = sum[1] > (255 * divisor) ? 255 : sum[1] / divisor; + temp_buf[(top + (i - dest->height)) * dest_rowstride].val[2] = sum[2] > (255 * divisor) ? 255 : sum[2] / divisor; + temp_buf[(top + (i - dest->height)) * dest_rowstride].val[3] = sum[3] > (255 * divisor) ? 255 : sum[3] / divisor; + } else { + dest_buf[i * dest_rowstride].val[0] = sum[0] > (255 * divisor) ? 255 : sum[0] / divisor; + dest_buf[i * dest_rowstride].val[1] = sum[1] > (255 * divisor) ? 255 : sum[1] / divisor; + dest_buf[i * dest_rowstride].val[2] = sum[2] > (255 * divisor) ? 255 : sum[2] / divisor; + dest_buf[i * dest_rowstride].val[3] = sum[3] > (255 * divisor) ? 255 : sum[3] / divisor; + } + + src_j++; + + for (uint32_t j = 1; j < dest->width; ++j, src_j++) { + if (j <= start_j) { + divisor++; + sum[0] += src_buf[src_i * src_rowstride + src_j + KW_d2].val[0]; + sum[1] += src_buf[src_i * src_rowstride + src_j + KW_d2].val[1]; + sum[2] += src_buf[src_i * src_rowstride + src_j + KW_d2].val[2]; + sum[3] += src_buf[src_i * src_rowstride + src_j + KW_d2].val[3]; + } else if (j <= end_j) { + sum[0] += src_buf[src_i * src_rowstride + src_j + KW_d2].val[0] + - src_buf[src_i * src_rowstride + src_j - KW_d2 - 1].val[0]; + sum[1] += src_buf[src_i * src_rowstride + src_j + KW_d2].val[1] + - src_buf[src_i * src_rowstride + src_j - KW_d2 - 1].val[1]; + sum[2] += src_buf[src_i * src_rowstride + src_j + KW_d2].val[2] + - src_buf[src_i * src_rowstride + src_j - KW_d2 - 1].val[2]; + sum[3] += src_buf[src_i * src_rowstride + src_j + KW_d2].val[3] + - src_buf[src_i * src_rowstride + src_j - KW_d2 - 1].val[3]; + } else { + divisor--; + sum[0] -= src_buf[src_i * src_rowstride + src_j - KW_d2 - 1].val[0]; + sum[1] -= src_buf[src_i * src_rowstride + src_j - KW_d2 - 1].val[1]; + sum[2] -= src_buf[src_i * src_rowstride + src_j - KW_d2 - 1].val[2]; + sum[3] -= src_buf[src_i * src_rowstride + src_j - KW_d2 - 1].val[3]; + } + + if (i < 0) { + temp_buf[(top + i) * dest_rowstride + j].val[0] = sum[0] > (255 * divisor) ? 255 : sum[0] / divisor; + temp_buf[(top + i) * dest_rowstride + j].val[1] = sum[1] > (255 * divisor) ? 255 : sum[1] / divisor; + temp_buf[(top + i) * dest_rowstride + j].val[2] = sum[2] > (255 * divisor) ? 255 : sum[2] / divisor; + temp_buf[(top + i) * dest_rowstride + j].val[3] = sum[3] > (255 * divisor) ? 255 : sum[3] / divisor; + } else if (i >= static_cast(dest->height)) { + temp_buf[(top + (i - dest->height)) * dest_rowstride + j].val[0] + = sum[0] > (255 * divisor) ? 255 : sum[0] / divisor; + temp_buf[(top + (i - dest->height)) * dest_rowstride + j].val[1] + = sum[1] > (255 * divisor) ? 255 : sum[1] / divisor; + temp_buf[(top + (i - dest->height)) * dest_rowstride + j].val[2] + = sum[2] > (255 * divisor) ? 255 : sum[2] / divisor; + temp_buf[(top + (i - dest->height)) * dest_rowstride + j].val[3] + = sum[3] > (255 * divisor) ? 255 : sum[3] / divisor; + } else { + dest_buf[i * dest_rowstride + j].val[0] = sum[0] > (255 * divisor) ? 255 : sum[0] / divisor; + dest_buf[i * dest_rowstride + j].val[1] = sum[1] > (255 * divisor) ? 255 : sum[1] / divisor; + dest_buf[i * dest_rowstride + j].val[2] = sum[2] > (255 * divisor) ? 255 : sum[2] / divisor; + dest_buf[i * dest_rowstride + j].val[3] = sum[3] > (255 * divisor) ? 255 : sum[3] / divisor; + } + } + } + + // Second pass (vertical) + for (uint32_t j = 0; j < dest->width; ++j) { + sum[0] = 0; + sum[1] = 0; + sum[2] = 0; + sum[3] = 0; + divisor = kernel_height - start_i; + + for (int k = start_i - KH_d2; k < 0; ++k) { + sum[0] += temp_buf[(top + k) * dest_rowstride + j].val[0]; + sum[1] += temp_buf[(top + k) * dest_rowstride + j].val[1]; + sum[2] += temp_buf[(top + k) * dest_rowstride + j].val[2]; + sum[3] += temp_buf[(top + k) * dest_rowstride + j].val[3]; + } + + for (int k = 0; k <= KH_d2; ++k) { + sum[0] += dest_buf[k * dest_rowstride + j].val[0]; + sum[1] += dest_buf[k * dest_rowstride + j].val[1]; + sum[2] += dest_buf[k * dest_rowstride + j].val[2]; + sum[3] += dest_buf[k * dest_rowstride + j].val[3]; + } + + temp_buf[(top + below) * dest_rowstride].val[0] = sum[0] > (255 * divisor) ? 255 : sum[0] / divisor; + temp_buf[(top + below) * dest_rowstride].val[1] = sum[1] > (255 * divisor) ? 255 : sum[1] / divisor; + temp_buf[(top + below) * dest_rowstride].val[2] = sum[2] > (255 * divisor) ? 255 : sum[2] / divisor; + temp_buf[(top + below) * dest_rowstride].val[3] = sum[3] > (255 * divisor) ? 255 : sum[3] / divisor; + + for (int i = 1; i < static_cast(dest->height); ++i) { + if (i > static_cast(start_i)) { + divisor--; + if (i - KH_d2 - 1 < 0) { + sum[0] -= temp_buf[(top + (i - KH_d2 - 1)) * dest_rowstride + j].val[0]; + sum[1] -= temp_buf[(top + (i - KH_d2 - 1)) * dest_rowstride + j].val[1]; + sum[2] -= temp_buf[(top + (i - KH_d2 - 1)) * dest_rowstride + j].val[2]; + sum[3] -= temp_buf[(top + (i - KH_d2 - 1)) * dest_rowstride + j].val[3]; + } else { + sum[0] -= dest_buf[(i - KH_d2 - 1) * dest_rowstride + j].val[0]; + sum[1] -= dest_buf[(i - KH_d2 - 1) * dest_rowstride + j].val[1]; + sum[2] -= dest_buf[(i - KH_d2 - 1) * dest_rowstride + j].val[2]; + sum[3] -= dest_buf[(i - KH_d2 - 1) * dest_rowstride + j].val[3]; + } + } + + if (i <= static_cast(end_i)) { + divisor++; + if (i + KH_d2 >= static_cast(dest->height)) { + sum[0] += temp_buf[(top + (i + KH_d2) - dest->height) * dest_rowstride + j].val[0]; + sum[1] += temp_buf[(top + (i + KH_d2) - dest->height) * dest_rowstride + j].val[1]; + sum[2] += temp_buf[(top + (i + KH_d2) - dest->height) * dest_rowstride + j].val[2]; + sum[3] += temp_buf[(top + (i + KH_d2) - dest->height) * dest_rowstride + j].val[3]; + } else { + sum[0] += dest_buf[(i + KH_d2) * dest_rowstride + j].val[0]; + sum[1] += dest_buf[(i + KH_d2) * dest_rowstride + j].val[1]; + sum[2] += dest_buf[(i + KH_d2) * dest_rowstride + j].val[2]; + sum[3] += dest_buf[(i + KH_d2) * dest_rowstride + j].val[3]; + } + } + + temp_buf[(top + below) * dest_rowstride + i].val[0] = sum[0] > (255 * divisor) ? 255 : sum[0] / divisor; + temp_buf[(top + below) * dest_rowstride + i].val[1] = sum[1] > (255 * divisor) ? 255 : sum[1] / divisor; + temp_buf[(top + below) * dest_rowstride + i].val[2] = sum[2] > (255 * divisor) ? 255 : sum[2] / divisor; + temp_buf[(top + below) * dest_rowstride + i].val[3] = sum[3] > (255 * divisor) ? 255 : sum[3] / divisor; + } + + for (uint32_t i = 0; i < dest->height; ++i) { + dest_buf[i * dest_rowstride + j] = temp_buf[(top + below) * dest_rowstride + i]; + } + } + } + + // This block deals with code for flag kvImageBackgroundColorFill, which requires all pixels outside image to be + // set to the parameter backgroundColor + else if (flags & kvImageBackgroundColorFill) { + + if (backgroundColor == nullptr) { + return kvImageNullPointerArgument; + } + + // First pass (horizontal) + for (int i = static_cast(start_i) - KH_d2; i <= static_cast(end_i) + KH_d2; ++i) { + src_i = srcOffsetToROI_Y + i; + src_j = srcOffsetToROI_X; + sum[0] = backgroundColor[0] * start_j; + sum[1] = backgroundColor[1] * start_j; + sum[2] = backgroundColor[2] * start_j; + sum[3] = backgroundColor[3] * start_j; + + for (int k = start_j - KW_d2; k <= KW_d2; ++k) { + sum[0] += src_buf[src_i * src_rowstride + src_j + k].val[0]; + sum[1] += src_buf[src_i * src_rowstride + src_j + k].val[1]; + sum[2] += src_buf[src_i * src_rowstride + src_j + k].val[2]; + sum[3] += src_buf[src_i * src_rowstride + src_j + k].val[3]; + } + + if (i<0) { + temp_buf[(top + i) * dest_rowstride].val[0] = sum[0] > (255 * kernel_width) ? 255 : sum[0] / kernel_width; + temp_buf[(top + i) * dest_rowstride].val[1] = sum[1] > (255 * kernel_width) ? 255 : sum[1] / kernel_width; + temp_buf[(top + i) * dest_rowstride].val[2] = sum[2] > (255 * kernel_width) ? 255 : sum[2] / kernel_width; + temp_buf[(top + i) * dest_rowstride].val[3] = sum[3] > (255 * kernel_width) ? 255 : sum[3] / kernel_width; + } else if (i >= static_cast(dest->height)) { + temp_buf[(top + (i - dest->height)) * dest_rowstride].val[0] + = sum[0] > (255 * kernel_width) ? 255 : sum[0] / kernel_width; + temp_buf[(top + (i - dest->height)) * dest_rowstride].val[1] + = sum[1] > (255 * kernel_width) ? 255 : sum[1] / kernel_width; + temp_buf[(top + (i - dest->height)) * dest_rowstride].val[2] + = sum[2] > (255 * kernel_width) ? 255 : sum[2] / kernel_width; + temp_buf[(top + (i - dest->height)) * dest_rowstride].val[3] + = sum[3] > (255 * kernel_width) ? 255 : sum[3] / kernel_width; + } else { + dest_buf[i * dest_rowstride].val[0] = sum[0] > (255 * kernel_width) ? 255 : sum[0] / kernel_width; + dest_buf[i * dest_rowstride].val[1] = sum[1] > (255 * kernel_width) ? 255 : sum[1] / kernel_width; + dest_buf[i * dest_rowstride].val[2] = sum[2] > (255 * kernel_width) ? 255 : sum[2] / kernel_width; + dest_buf[i * dest_rowstride].val[3] = sum[3] > (255 * kernel_width) ? 255 : sum[3] / kernel_width; + } + + src_j++; + + for (uint32_t j = 1; j < dest->width; ++j, src_j++) { + if (j <= start_j) { + sum[0] += src_buf[src_i * src_rowstride + src_j + KW_d2].val[0] - backgroundColor[0]; + sum[1] += src_buf[src_i * src_rowstride + src_j + KW_d2].val[1] - backgroundColor[1]; + sum[2] += src_buf[src_i * src_rowstride + src_j + KW_d2].val[2] - backgroundColor[2]; + sum[3] += src_buf[src_i * src_rowstride + src_j + KW_d2].val[3] - backgroundColor[3]; + } else if (j <= end_j) { + sum[0] += src_buf[src_i * src_rowstride + src_j + KW_d2].val[0] + - src_buf[src_i * src_rowstride + src_j - KW_d2 - 1].val[0]; + sum[1] += src_buf[src_i * src_rowstride + src_j + KW_d2].val[1] + - src_buf[src_i * src_rowstride + src_j - KW_d2 - 1].val[1]; + sum[2] += src_buf[src_i * src_rowstride + src_j + KW_d2].val[2] + - src_buf[src_i * src_rowstride + src_j - KW_d2 - 1].val[2]; + sum[3] += src_buf[src_i * src_rowstride + src_j + KW_d2].val[3] + - src_buf[src_i * src_rowstride + src_j - KW_d2 - 1].val[3]; + } else { + sum[0] += -src_buf[src_i * src_rowstride + src_j - KW_d2 - 1].val[0] + backgroundColor[0]; + sum[1] += -src_buf[src_i * src_rowstride + src_j - KW_d2 - 1].val[1] + backgroundColor[1]; + sum[2] += -src_buf[src_i * src_rowstride + src_j - KW_d2 - 1].val[2] + backgroundColor[2]; + sum[3] += -src_buf[src_i * src_rowstride + src_j - KW_d2 - 1].val[3] + backgroundColor[3]; + } + + if (i < 0) { + temp_buf[(top + i) * dest_rowstride + j].val[0] = sum[0] > (255 * kernel_width) ? 255 : sum[0] / kernel_width; + temp_buf[(top + i) * dest_rowstride + j].val[1] = sum[1] > (255 * kernel_width) ? 255 : sum[1] / kernel_width; + temp_buf[(top + i) * dest_rowstride + j].val[2] = sum[2] > (255 * kernel_width) ? 255 : sum[2] / kernel_width; + temp_buf[(top + i) * dest_rowstride + j].val[3] = sum[3] > (255 * kernel_width) ? 255 : sum[3] / kernel_width; + } else if (i >= static_cast(dest->height)) { + temp_buf[(top + (i - dest->height)) * dest_rowstride + j].val[0] + = sum[0] > (255 * kernel_width) ? 255 : sum[0] / kernel_width; + temp_buf[(top + (i - dest->height)) * dest_rowstride + j].val[1] + = sum[1] > (255 * kernel_width) ? 255 : sum[1] / kernel_width; + temp_buf[(top + (i - dest->height)) * dest_rowstride + j].val[2] + = sum[2] > (255 * kernel_width) ? 255 : sum[2] / kernel_width; + temp_buf[(top + (i - dest->height)) * dest_rowstride + j].val[3] + = sum[3] > (255 * kernel_width) ? 255 : sum[3] / kernel_width; + } else { + dest_buf[i * dest_rowstride + j].val[0] = sum[0] > (255 * kernel_width) ? 255 : sum[0] / kernel_width; + dest_buf[i * dest_rowstride + j].val[1] = sum[1] > (255 * kernel_width) ? 255 : sum[1] / kernel_width; + dest_buf[i * dest_rowstride + j].val[2] = sum[2] > (255 * kernel_width) ? 255 : sum[2] / kernel_width; + dest_buf[i * dest_rowstride + j].val[3] = sum[3] > (255 * kernel_width) ? 255 : sum[3] / kernel_width; + } + } + } + + // Second pass (vertical) + for (uint32_t j = 0; j < dest->width; ++j) { + sum[0] = backgroundColor[0] * start_i; + sum[1] = backgroundColor[1] * start_i; + sum[2] = backgroundColor[2] * start_i; + sum[3] = backgroundColor[3] * start_i; + + for (int k = start_i - KH_d2; k < 0; ++k) { + sum[0] += temp_buf[(top + k) * dest_rowstride + j].val[0]; + sum[1] += temp_buf[(top + k) * dest_rowstride + j].val[1]; + sum[2] += temp_buf[(top + k) * dest_rowstride + j].val[2]; + sum[3] += temp_buf[(top + k) * dest_rowstride + j].val[3]; + } + + for (int k = 0; k <= KH_d2; ++k) { + sum[0] += dest_buf[k * dest_rowstride + j].val[0]; + sum[1] += dest_buf[k * dest_rowstride + j].val[1]; + sum[2] += dest_buf[k * dest_rowstride + j].val[2]; + sum[3] += dest_buf[k * dest_rowstride + j].val[3]; + } + + temp_buf[(top + below) * dest_rowstride].val[0] = sum[0] > (255 * kernel_height) ? 255 : sum[0] / kernel_height; + temp_buf[(top + below) * dest_rowstride].val[1] = sum[1] > (255 * kernel_height) ? 255 : sum[1] / kernel_height; + temp_buf[(top + below) * dest_rowstride].val[2] = sum[2] > (255 * kernel_height) ? 255 : sum[2] / kernel_height; + temp_buf[(top + below) * dest_rowstride].val[3] = sum[3] > (255 * kernel_height) ? 255 : sum[3] / kernel_height; + + for (int i = 1; i < static_cast(dest->height); ++i) { + if (i <= static_cast(start_i)) { + sum[0] -= backgroundColor[0]; + sum[1] -= backgroundColor[1]; + sum[2] -= backgroundColor[2]; + sum[3] -= backgroundColor[3]; + } else if (i <= KH_d2) { + sum[0] -= temp_buf[(top + (i - KH_d2 - 1)) * dest_rowstride + j].val[0]; + sum[1] -= temp_buf[(top + (i - KH_d2 - 1)) * dest_rowstride + j].val[1]; + sum[2] -= temp_buf[(top + (i - KH_d2 - 1)) * dest_rowstride + j].val[2]; + sum[3] -= temp_buf[(top + (i - KH_d2 - 1)) * dest_rowstride + j].val[3]; + } else { + sum[0] -= dest_buf[(i - KH_d2 - 1) * dest_rowstride + j].val[0]; + sum[1] -= dest_buf[(i - KH_d2 - 1) * dest_rowstride + j].val[1]; + sum[2] -= dest_buf[(i - KH_d2 - 1) * dest_rowstride + j].val[2]; + sum[3] -= dest_buf[(i - KH_d2 - 1) * dest_rowstride + j].val[3]; + } + + if (i > static_cast(end_i)) { + sum[0] += backgroundColor[0]; + sum[1] += backgroundColor[1]; + sum[2] += backgroundColor[2]; + sum[3] += backgroundColor[3]; + } else if (i >= static_cast(dest->height) - KH_d2) { + sum[0] += temp_buf[(top + (i + KH_d2) - dest->height) * dest_rowstride + j].val[0]; + sum[1] += temp_buf[(top + (i + KH_d2) - dest->height) * dest_rowstride + j].val[1]; + sum[2] += temp_buf[(top + (i + KH_d2) - dest->height) * dest_rowstride + j].val[2]; + sum[3] += temp_buf[(top + (i + KH_d2) - dest->height) * dest_rowstride + j].val[3]; + } else { + sum[0] += dest_buf[(i + KH_d2) * dest_rowstride + j].val[0]; + sum[1] += dest_buf[(i + KH_d2) * dest_rowstride + j].val[1]; + sum[2] += dest_buf[(i + KH_d2) * dest_rowstride + j].val[2]; + sum[3] += dest_buf[(i + KH_d2) * dest_rowstride + j].val[3]; + } + + temp_buf[(top + below) * dest_rowstride + i].val[0] = sum[0] > (255 * kernel_height) ? 255 : sum[0] / kernel_height; + temp_buf[(top + below) * dest_rowstride + i].val[1] = sum[1] > (255 * kernel_height) ? 255 : sum[1] / kernel_height; + temp_buf[(top + below) * dest_rowstride + i].val[2] = sum[2] > (255 * kernel_height) ? 255 : sum[2] / kernel_height; + temp_buf[(top + below) * dest_rowstride + i].val[3] = sum[3] > (255 * kernel_height) ? 255 : sum[3] / kernel_height; + } + + for (uint32_t i = 0; i < dest->height; ++i) { + dest_buf[i * dest_rowstride + j] = temp_buf[(top + below) * dest_rowstride + i]; + } + } + } + + // This block deals with code for flag kvImageEdgeExtend, which requires all pixels outside image to be + // replicated by the edges of the image outwards. + else if (flags & kvImageEdgeExtend) { + + // For storing the first and the last pixel if the image is to be extended + Pixel_8888_s first_pixel; + Pixel_8888_s last_pixel; + + // First pass (horizontal) + for (int i = static_cast(start_i) - KH_d2; i <= static_cast(end_i) + KH_d2; ++i) { + src_i = srcOffsetToROI_Y + i; + src_j = srcOffsetToROI_X; + first_pixel = src_buf[src_i * src_rowstride + src_j + (start_j - KW_d2)]; + last_pixel = src_buf[src_i * src_rowstride + src_j + end_j + KW_d2]; + sum[0] = first_pixel.val[0] * start_j; + sum[1] = first_pixel.val[1] * start_j; + sum[2] = first_pixel.val[2] * start_j; + sum[3] = first_pixel.val[3] * start_j; + + for (int k = start_j - KW_d2; k <= KW_d2; ++k) { + sum[0] += src_buf[src_i * src_rowstride + src_j + k].val[0]; + sum[1] += src_buf[src_i * src_rowstride + src_j + k].val[1]; + sum[2] += src_buf[src_i * src_rowstride + src_j + k].val[2]; + sum[3] += src_buf[src_i * src_rowstride + src_j + k].val[3]; + } + + if (i<0) { + temp_buf[(top + i) * dest_rowstride].val[0] = sum[0] > (255 * kernel_width) ? 255 : sum[0] / kernel_width; + temp_buf[(top + i) * dest_rowstride].val[1] = sum[1] > (255 * kernel_width) ? 255 : sum[1] / kernel_width; + temp_buf[(top + i) * dest_rowstride].val[2] = sum[2] > (255 * kernel_width) ? 255 : sum[2] / kernel_width; + temp_buf[(top + i) * dest_rowstride].val[3] = sum[3] > (255 * kernel_width) ? 255 : sum[3] / kernel_width; + } else if (i >= static_cast(dest->height)) { + temp_buf[(top + (i - dest->height)) * dest_rowstride].val[0] + = sum[0] > (255 * kernel_width) ? 255 : sum[0] / kernel_width; + temp_buf[(top + (i - dest->height)) * dest_rowstride].val[1] + = sum[1] > (255 * kernel_width) ? 255 : sum[1] / kernel_width; + temp_buf[(top + (i - dest->height)) * dest_rowstride].val[2] + = sum[2] > (255 * kernel_width) ? 255 : sum[2] / kernel_width; + temp_buf[(top + (i - dest->height)) * dest_rowstride].val[3] + = sum[3] > (255 * kernel_width) ? 255 : sum[3] / kernel_width; + } else { + dest_buf[i * dest_rowstride].val[0] = sum[0] > (255 * kernel_width) ? 255 : sum[0] / kernel_width; + dest_buf[i * dest_rowstride].val[1] = sum[1] > (255 * kernel_width) ? 255 : sum[1] / kernel_width; + dest_buf[i * dest_rowstride].val[2] = sum[2] > (255 * kernel_width) ? 255 : sum[2] / kernel_width; + dest_buf[i * dest_rowstride].val[3] = sum[3] > (255 * kernel_width) ? 255 : sum[3] / kernel_width; + } + + src_j++; + + for (uint32_t j = 1; j < dest->width; ++j, src_j++) { + if (j <= start_j) { + sum[0] += src_buf[src_i * src_rowstride + src_j + KW_d2].val[0] - first_pixel.val[0]; + sum[1] += src_buf[src_i * src_rowstride + src_j + KW_d2].val[1] - first_pixel.val[1]; + sum[2] += src_buf[src_i * src_rowstride + src_j + KW_d2].val[2] - first_pixel.val[2]; + sum[3] += src_buf[src_i * src_rowstride + src_j + KW_d2].val[3] - first_pixel.val[3]; + } else if (j <= end_j) { + sum[0] += src_buf[src_i * src_rowstride + src_j + KW_d2].val[0] + - src_buf[src_i * src_rowstride + src_j - KW_d2 - 1].val[0]; + sum[1] += src_buf[src_i * src_rowstride + src_j + KW_d2].val[1] + - src_buf[src_i * src_rowstride + src_j - KW_d2 - 1].val[1]; + sum[2] += src_buf[src_i * src_rowstride + src_j + KW_d2].val[2] + - src_buf[src_i * src_rowstride + src_j - KW_d2 - 1].val[2]; + sum[3] += src_buf[src_i * src_rowstride + src_j + KW_d2].val[3] + - src_buf[src_i * src_rowstride + src_j - KW_d2 - 1].val[3]; + } else { + sum[0] += last_pixel.val[0] - src_buf[src_i * src_rowstride + src_j - KW_d2 - 1].val[0]; + sum[1] += last_pixel.val[1] - src_buf[src_i * src_rowstride + src_j - KW_d2 - 1].val[1]; + sum[2] += last_pixel.val[2] - src_buf[src_i * src_rowstride + src_j - KW_d2 - 1].val[2]; + sum[3] += last_pixel.val[3] - src_buf[src_i * src_rowstride + src_j - KW_d2 - 1].val[3]; + } + + if (i < 0) { + temp_buf[(top + i) * dest_rowstride + j].val[0] = sum[0] > (255 * kernel_width) ? 255 : sum[0] / kernel_width; + temp_buf[(top + i) * dest_rowstride + j].val[1] = sum[1] > (255 * kernel_width) ? 255 : sum[1] / kernel_width; + temp_buf[(top + i) * dest_rowstride + j].val[2] = sum[2] > (255 * kernel_width) ? 255 : sum[2] / kernel_width; + temp_buf[(top + i) * dest_rowstride + j].val[3] = sum[3] > (255 * kernel_width) ? 255 : sum[3] / kernel_width; + } else if (i >= static_cast(dest->height)) { + temp_buf[(top + (i - dest->height)) * dest_rowstride + j].val[0] + = sum[0] > (255 * kernel_width) ? 255 : sum[0] / kernel_width; + temp_buf[(top + (i - dest->height)) * dest_rowstride + j].val[1] + = sum[1] > (255 * kernel_width) ? 255 : sum[1] / kernel_width; + temp_buf[(top + (i - dest->height)) * dest_rowstride + j].val[2] + = sum[2] > (255 * kernel_width) ? 255 : sum[2] / kernel_width; + temp_buf[(top + (i - dest->height)) * dest_rowstride + j].val[3] + = sum[3] > (255 * kernel_width) ? 255 : sum[3] / kernel_width; + } else { + dest_buf[i * dest_rowstride + j].val[0] = sum[0] > (255 * kernel_width) ? 255 : sum[0] / kernel_width; + dest_buf[i * dest_rowstride + j].val[1] = sum[1] > (255 * kernel_width) ? 255 : sum[1] / kernel_width; + dest_buf[i * dest_rowstride + j].val[2] = sum[2] > (255 * kernel_width) ? 255 : sum[2] / kernel_width; + dest_buf[i * dest_rowstride + j].val[3] = sum[3] > (255 * kernel_width) ? 255 : sum[3] / kernel_width; + } + } + } + + // Second pass (vertical) + for (uint32_t j = 0; j < dest->width; ++j) { + if (top > 0) { + first_pixel = temp_buf[j]; + } else { + first_pixel = dest_buf[j]; + } + + if (below > 0) { + last_pixel = temp_buf[(top + below - 1) * dest_rowstride + j]; + } else { + last_pixel = dest_buf[(dest->height - 1) * dest_rowstride + j]; + } + + sum[0] = first_pixel.val[0] * start_i; + sum[1] = first_pixel.val[1] * start_i; + sum[2] = first_pixel.val[2] * start_i; + sum[3] = first_pixel.val[3] * start_i; + + for (int k = start_i - KH_d2; k < 0; ++k) { + sum[0] += temp_buf[(top + k) * dest_rowstride + j].val[0]; + sum[1] += temp_buf[(top + k) * dest_rowstride + j].val[1]; + sum[2] += temp_buf[(top + k) * dest_rowstride + j].val[2]; + sum[3] += temp_buf[(top + k) * dest_rowstride + j].val[3]; + } + + for (int k = 0; k <= KH_d2; ++k) { + sum[0] += dest_buf[k * dest_rowstride + j].val[0]; + sum[1] += dest_buf[k * dest_rowstride + j].val[1]; + sum[2] += dest_buf[k * dest_rowstride + j].val[2]; + sum[3] += dest_buf[k * dest_rowstride + j].val[3]; + } + + temp_buf[(top + below) * dest_rowstride].val[0] = sum[0] > (255 * kernel_height) ? 255 : sum[0] / kernel_height; + temp_buf[(top + below) * dest_rowstride].val[1] = sum[1] > (255 * kernel_height) ? 255 : sum[1] / kernel_height; + temp_buf[(top + below) * dest_rowstride].val[2] = sum[2] > (255 * kernel_height) ? 255 : sum[2] / kernel_height; + temp_buf[(top + below) * dest_rowstride].val[3] = sum[3] > (255 * kernel_height) ? 255 : sum[3] / kernel_height; + + for (int i = 1; i < static_cast(dest->height); ++i) { + if (i <= static_cast(start_i)) { + sum[0] -= first_pixel.val[0]; + sum[1] -= first_pixel.val[1]; + sum[2] -= first_pixel.val[2]; + sum[3] -= first_pixel.val[3]; + } else if (i <= KH_d2) { + sum[0] -= temp_buf[(top + (i - KH_d2 - 1)) * dest_rowstride + j].val[0]; + sum[1] -= temp_buf[(top + (i - KH_d2 - 1)) * dest_rowstride + j].val[1]; + sum[2] -= temp_buf[(top + (i - KH_d2 - 1)) * dest_rowstride + j].val[2]; + sum[3] -= temp_buf[(top + (i - KH_d2 - 1)) * dest_rowstride + j].val[3]; + } else { + sum[0] -= dest_buf[(i - KH_d2 - 1) * dest_rowstride + j].val[0]; + sum[1] -= dest_buf[(i - KH_d2 - 1) * dest_rowstride + j].val[1]; + sum[2] -= dest_buf[(i - KH_d2 - 1) * dest_rowstride + j].val[2]; + sum[3] -= dest_buf[(i - KH_d2 - 1) * dest_rowstride + j].val[3]; + } + + if (i > static_cast(end_i)) { + sum[0] += last_pixel.val[0]; + sum[1] += last_pixel.val[1]; + sum[2] += last_pixel.val[2]; + sum[3] += last_pixel.val[3]; + } else if (i >= static_cast(dest->height) - KH_d2) { + sum[0] += temp_buf[(top + (i + KH_d2) - dest->height) * dest_rowstride + j].val[0]; + sum[1] += temp_buf[(top + (i + KH_d2) - dest->height) * dest_rowstride + j].val[1]; + sum[2] += temp_buf[(top + (i + KH_d2) - dest->height) * dest_rowstride + j].val[2]; + sum[3] += temp_buf[(top + (i + KH_d2) - dest->height) * dest_rowstride + j].val[3]; + } else { + sum[0] += dest_buf[(i + KH_d2) * dest_rowstride + j].val[0]; + sum[1] += dest_buf[(i + KH_d2) * dest_rowstride + j].val[1]; + sum[2] += dest_buf[(i + KH_d2) * dest_rowstride + j].val[2]; + sum[3] += dest_buf[(i + KH_d2) * dest_rowstride + j].val[3]; + } + + temp_buf[(top + below) * dest_rowstride + i].val[0] = sum[0] > (255 * kernel_height) ? 255 : sum[0] / kernel_height; + temp_buf[(top + below) * dest_rowstride + i].val[1] = sum[1] > (255 * kernel_height) ? 255 : sum[1] / kernel_height; + temp_buf[(top + below) * dest_rowstride + i].val[2] = sum[2] > (255 * kernel_height) ? 255 : sum[2] / kernel_height; + temp_buf[(top + below) * dest_rowstride + i].val[3] = sum[3] > (255 * kernel_height) ? 255 : sum[3] / kernel_height; + } + + for (uint32_t i = 0; i < dest->height; ++i) { + dest_buf[i * dest_rowstride + j] = temp_buf[(top + below) * dest_rowstride + i]; + } + } + } else { + return kvImageUnknownFlagsBit; + } + + // Deallocating the temporary buffer + if (tempBuffer_flag == 1) { + delete[] temp_buf; + } + + return kvImageNoError; +} + + +vImage_Error vImageMatrixMultiply_ARGB8888(const vImage_Buffer* src, + const vImage_Buffer* dest, + const int16_t matrix[16], + int32_t divisor, + const int16_t* pre_bias_p, + const int32_t* post_bias_p, + vImage_Flags flags) { + int32_t m00 = matrix[0]; + int32_t m01 = matrix[1]; + int32_t m02 = matrix[2]; + int32_t m03 = matrix[3]; + int32_t m10 = matrix[4]; + int32_t m11 = matrix[5]; + int32_t m12 = matrix[6]; + int32_t m13 = matrix[7]; + int32_t m20 = matrix[8]; + int32_t m21 = matrix[9]; + int32_t m22 = matrix[10]; + int32_t m23 = matrix[11]; + int32_t m30 = matrix[12]; + int32_t m31 = matrix[13]; + int32_t m32 = matrix[14]; + int32_t m33 = matrix[15]; + int32_t post_b0 = post_bias_p ? post_bias_p[0] : 0; + int32_t post_b1 = post_bias_p ? post_bias_p[1] : 0; + int32_t post_b2 = post_bias_p ? post_bias_p[2] : 0; + int32_t post_b3 = post_bias_p ? post_bias_p[3] : 0; + vImagePixelCount height = src->height; + vImagePixelCount width = src->width; + const Pixel_8888_s* in = static_cast(src->data); + size_t in_rowstride = src->rowBytes / sizeof(Pixel_8888); + Pixel_8888_s* out = static_cast(dest->data); + size_t out_rowstride = dest->rowBytes / sizeof(Pixel_8888); + + if (!in || !out) { + return kvImageNullPointerArgument; + } else if (height != dest->height || width != dest->width) { + return kvImageInvalidParameter; + } + + if (pre_bias_p) { + int32_t pre_b0 = pre_bias_p[0]; + int32_t pre_b1 = pre_bias_p[1]; + int32_t pre_b2 = pre_bias_p[2]; + int32_t pre_b3 = pre_bias_p[3]; + + for (vImagePixelCount i = 0; i < height; ++i) { + + for (vImagePixelCount j = 0; j < width; ++j) { + struct Pixel_8888_s pixel = in[i * in_rowstride + j]; + int32_t prod[4]; + pixel.val[0] += pre_b0; + pixel.val[1] += pre_b1; + pixel.val[2] += pre_b2; + pixel.val[3] += pre_b3; + prod[0] = pixel.val[0] * m00 + pixel.val[1] * m10 + pixel.val[2] * m20 + pixel.val[3] * m30 + post_b0; + prod[1] = pixel.val[0] * m01 + pixel.val[1] * m11 + pixel.val[2] * m21 + pixel.val[3] * m31 + post_b1; + prod[2] = pixel.val[0] * m02 + pixel.val[1] * m12 + pixel.val[2] * m22 + pixel.val[3] * m32 + post_b2; + prod[3] = pixel.val[0] * m03 + pixel.val[1] * m13 + pixel.val[2] * m23 + pixel.val[3] * m33 + post_b3; + + if (divisor != 1) { + prod[0] /= divisor; + prod[1] /= divisor; + prod[2] /= divisor; + prod[3] /= divisor; + } + + pixel.val[0] = prod[0] > 255 ? 255 : prod[0] < 0 ? 0 : prod[0]; + pixel.val[1] = prod[1] > 255 ? 255 : prod[1] < 0 ? 0 : prod[1]; + pixel.val[2] = prod[2] > 255 ? 255 : prod[2] < 0 ? 0 : prod[2]; + pixel.val[3] = prod[3] > 255 ? 255 : prod[3] < 0 ? 0 : prod[3]; + + out[i * out_rowstride + j] = pixel; + } + } + } else { + + for (vImagePixelCount i = 0; i < height; ++i) { + + for (vImagePixelCount j = 0; j < width; ++j) { + struct Pixel_8888_s pixel = in[i * in_rowstride + j]; + int32_t prod[4]; + prod[0] = pixel.val[0] * m00 + pixel.val[1] * m10 + pixel.val[2] * m20 + pixel.val[3] * m30 + post_b0; + prod[1] = pixel.val[0] * m01 + pixel.val[1] * m11 + pixel.val[2] * m21 + pixel.val[3] * m31 + post_b1; + prod[2] = pixel.val[0] * m02 + pixel.val[1] * m12 + pixel.val[2] * m22 + pixel.val[3] * m32 + post_b2; + prod[3] = pixel.val[0] * m03 + pixel.val[1] * m13 + pixel.val[2] * m23 + pixel.val[3] * m33 + post_b3; + + if (divisor != 1) { + prod[0] /= divisor; + prod[1] /= divisor; + prod[2] /= divisor; + prod[3] /= divisor; + } + + pixel.val[0] = prod[0] > 255 ? 255 : prod[0] < 0 ? 0 : prod[0]; + pixel.val[1] = prod[1] > 255 ? 255 : prod[1] < 0 ? 0 : prod[1]; + pixel.val[2] = prod[2] > 255 ? 255 : prod[2] < 0 ? 0 : prod[2]; + pixel.val[3] = prod[3] > 255 ? 255 : prod[3] < 0 ? 0 : prod[3]; + + out[i * out_rowstride + j] = pixel; + } + } + } + + return kvImageNoError; +} \ No newline at end of file diff --git a/build/Accelerate/dll/Accelerate.def b/build/Accelerate/dll/Accelerate.def index c7072f918b..a3d3312bdd 100644 --- a/build/Accelerate/dll/Accelerate.def +++ b/build/Accelerate/dll/Accelerate.def @@ -231,4 +231,14 @@ LIBRARY Accelerate cblas_zrotg cblas_zdrot SetBLASParamErrorProc - BLASDefaultErrorProc \ No newline at end of file + BLASDefaultErrorProc + vDSP_DFT_zop_CreateSetup + vDSP_DFT_zop_CreateSetupD + vDSP_DFT_zrop_CreateSetup + vDSP_DFT_zrop_CreateSetupD + vDSP_DFT_DestroySetup + vDSP_DFT_DestroySetupD + vDSP_DFT_Execute + vDSP_DFT_ExecuteD + vImageBoxConvolve_ARGB8888 + vImageMatrixMultiply_ARGB8888 \ No newline at end of file diff --git a/build/Accelerate/lib/AccelerateLib.vcxproj b/build/Accelerate/lib/AccelerateLib.vcxproj index 16636c2672..cfed91be4d 100644 --- a/build/Accelerate/lib/AccelerateLib.vcxproj +++ b/build/Accelerate/lib/AccelerateLib.vcxproj @@ -162,6 +162,7 @@ + {05EB0ADE-A598-42BA-BA3D-960AEEAA3C95} diff --git a/build/Tests/UnitTests/Accelerate/Accelerate.UnitTests.vcxproj b/build/Tests/UnitTests/Accelerate/Accelerate.UnitTests.vcxproj index da704418ed..1d77be61c4 100644 --- a/build/Tests/UnitTests/Accelerate/Accelerate.UnitTests.vcxproj +++ b/build/Tests/UnitTests/Accelerate/Accelerate.UnitTests.vcxproj @@ -144,6 +144,7 @@ + diff --git a/include/Accelerate/Accelerate.h b/include/Accelerate/Accelerate.h index 01c9d5ab15..0f813ebf8e 100644 --- a/include/Accelerate/Accelerate.h +++ b/include/Accelerate/Accelerate.h @@ -20,5 +20,5 @@ #include "vDSP.h" #include "cblas.h" #include "eigen.h" - +#include "vImage.h" diff --git a/include/Accelerate/vDSP.h b/include/Accelerate/vDSP.h index 497941f513..a5a6f49e6f 100644 --- a/include/Accelerate/vDSP.h +++ b/include/Accelerate/vDSP.h @@ -41,6 +41,31 @@ typedef struct { double* imagp; } DSPDoubleSplitComplex; +//Specifies whether to perform a Forward or inverse DFT +typedef enum { + vDSP_DFT_FORWARD = +1, + vDSP_DFT_INVERSE = -1 +} vDSP_DFT_Direction; + +//Specifies whether the DFT transformation is complex-to-complex or real-to-complex and vice versa for IDFT +typedef enum { + ZOP = 1, + ZROP = 2 +} vDSP_DFT_TransformType; + +//Setup object to be fed while computing the DFT/IDFT for a set of single-precision vectors +typedef struct vDSP_DFT_SetupStruct { + vDSP_Length transformLength; + vDSP_DFT_Direction transformDirection; + vDSP_DFT_TransformType transformType; +} *vDSP_DFT_Setup; + +//Setup object to be fed while computing the DFT/IDFT for a set of double-precision vectors +typedef struct vDSP_DFT_SetupStructD { + vDSP_Length transformLength; + vDSP_DFT_Direction transformDirection; + vDSP_DFT_TransformType transformType; +} *vDSP_DFT_SetupD; ACCELERATE_EXPORT void vDSP_vabs(const float* A, vDSP_Stride IA, float* C, vDSP_Stride IC, vDSP_Length N); ACCELERATE_EXPORT void vDSP_vabsD(const double* A, vDSP_Stride IA, double* C, vDSP_Stride IC, vDSP_Length N); @@ -166,4 +191,18 @@ ACCELERATE_EXPORT void vDSP_rmsqvD(const double *A, vDSP_Stride IA, double *C, v ACCELERATE_EXPORT void vDSP_ctoz(const DSPComplex *C, vDSP_Stride IC, const DSPSplitComplex *Z, vDSP_Stride IZ, vDSP_Length N); ACCELERATE_EXPORT void vDSP_ctozD(const DSPDoubleComplex *C, vDSP_Stride IC, const DSPDoubleSplitComplex *Z, vDSP_Stride IZ, vDSP_Length N); ACCELERATE_EXPORT void vDSP_blkman_window(float *C, vDSP_Length N, int Flag); -ACCELERATE_EXPORT void vDSP_blkman_windowD(double *C, vDSP_Length N, int Flag); \ No newline at end of file +ACCELERATE_EXPORT void vDSP_blkman_windowD(double *C, vDSP_Length N, int Flag); +ACCELERATE_EXPORT vDSP_DFT_Setup vDSP_DFT_zop_CreateSetup(vDSP_DFT_Setup __Previous, vDSP_Length __Length, + vDSP_DFT_Direction __Direction); +ACCELERATE_EXPORT vDSP_DFT_SetupD vDSP_DFT_zop_CreateSetupD(vDSP_DFT_SetupD __Previous, vDSP_Length __Length, + vDSP_DFT_Direction __Direction); +ACCELERATE_EXPORT vDSP_DFT_Setup vDSP_DFT_zrop_CreateSetup(vDSP_DFT_Setup __Previous, vDSP_Length __Length, + vDSP_DFT_Direction __Direction); +ACCELERATE_EXPORT vDSP_DFT_SetupD vDSP_DFT_zrop_CreateSetupD(vDSP_DFT_SetupD __Previous, vDSP_Length __Length, + vDSP_DFT_Direction __Direction); +ACCELERATE_EXPORT void vDSP_DFT_DestroySetup(vDSP_DFT_Setup __Setup); +ACCELERATE_EXPORT void vDSP_DFT_DestroySetupD(vDSP_DFT_SetupD __Setup); +ACCELERATE_EXPORT void vDSP_DFT_Execute(const struct vDSP_DFT_SetupStruct *__Setup, const float *__Ir, const float *__Ii, float *__Or, + float *__Oi); +ACCELERATE_EXPORT void vDSP_DFT_ExecuteD(const struct vDSP_DFT_SetupStructD *__Setup, const double *__Ir, const double *__Ii, double *__Or, + double *__Oi); \ No newline at end of file diff --git a/include/Accelerate/vImage.h b/include/Accelerate/vImage.h new file mode 100644 index 0000000000..03bb332843 --- /dev/null +++ b/include/Accelerate/vImage.h @@ -0,0 +1,85 @@ +//****************************************************************************** +// +// Copyright (c) 2016, Intel Corporation +// Copyright (c) 2015 Microsoft Corporation. All rights reserved. +// +// This code is licensed under the MIT License (MIT). +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +// +//****************************************************************************** + +#include +#include +#include "AccelerateExport.h" + +enum +{ + kvImageNoError = 0, + kvImageRoiLargerThanInputBuffer = -21766, + kvImageInvalidKernelSize = -21767, + kvImageInvalidEdgeStyle = -21768, + kvImageInvalidOffset_X = -21769, + kvImageInvalidOffset_Y = -21770, + kvImageMemoryAllocationError = -21771, + kvImageNullPointerArgument = -21772, + kvImageInvalidParameter = -21773, + kvImageBufferSizeMismatch = -21774, + kvImageUnknownFlagsBit = -21775 +}; + +enum +{ + kvImageNoFlags = 0, + kvImageLeaveAlphaUnchanged = 1, + kvImageCopyInPlace = 2, + kvImageBackgroundColorFill = 4, + kvImageEdgeExtend = 8, + kvImageDoNotTile = 16, + kvImageHighQualityResampling = 32, + kvImageTruncateKernel = 64, + kvImageGetTempBufferSize = 128 +}; + +typedef unsigned long vImagePixelCount; + +typedef struct { + void* data; + vImagePixelCount height; + vImagePixelCount width; + size_t rowBytes; +} vImage_Buffer; + +typedef SSIZE_T vImage_Error; + +typedef uint32_t vImage_Flags; + +typedef uint8_t Pixel_8888[4]; + +typedef struct Pixel_8888_s { + Pixel_8888 val; +} Pixel_8888_s; + +ACCELERATE_EXPORT vImage_Error vImageBoxConvolve_ARGB8888(const vImage_Buffer* src, + const vImage_Buffer* dest, + void* tempBuffer, + vImagePixelCount srcOffsetToROI_X, + vImagePixelCount srcOffsetToROI_Y, + uint32_t kernel_height, + uint32_t kernel_width, + const Pixel_8888 backgroundColor, + vImage_Flags flags); + +ACCELERATE_EXPORT vImage_Error vImageMatrixMultiply_ARGB8888(const vImage_Buffer* src, + const vImage_Buffer* dest, + const int16_t matrix[16], + int32_t divisor, + const int16_t* pre_bias_p, + const int32_t* post_bias_p, + vImage_Flags flags); \ No newline at end of file diff --git a/samples/WOCCatalog/WOCCatalog-WinStore10.sln b/samples/WOCCatalog/WOCCatalog-WinStore10.sln index d86775707e..c21a06298c 100644 --- a/samples/WOCCatalog/WOCCatalog-WinStore10.sln +++ b/samples/WOCCatalog/WOCCatalog-WinStore10.sln @@ -2,16 +2,16 @@ Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio 14 VisualStudioVersion = 14.0.24720.0 MinimumVisualStudioVersion = 10.0.40219.1 -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "WOCCatalog", "WOCCatalog", "{802EC330-1C66-4ECE-ACAC-A22F0058E869}" +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "WOCCatalog", "WOCCatalog", "{B2E97B00-7169-4019-A43B-2BBEE8A27371}" EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "WOCCatalog-Headers", "WOCCatalog.vsimporter\WOCCatalog-Headers-WinStore10\WOCCatalog-Headers.vcxitems", "{A74AAE3B-53F9-42FE-B857-87153273DA20}" +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "WOCCatalog-Headers", "WOCCatalog.vsimporter\WOCCatalog-Headers-WinStore10\WOCCatalog-Headers.vcxitems", "{6117D215-F749-41BD-834E-B5CC22B1784C}" EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "WOCCatalog", "WOCCatalog.vsimporter\WOCCatalog-WinStore10\WOCCatalog.vcxproj", "{BEF9B300-B97B-4E96-90AC-C7D0150A6ED7}" +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "WOCCatalog", "WOCCatalog.vsimporter\WOCCatalog-WinStore10\WOCCatalog.vcxproj", "{7ACE16A9-EA45-422A-80C9-0783F0ED4E9C}" EndProject Global GlobalSection(SharedMSBuildProjectFiles) = preSolution - WOCCatalog.vsimporter\WOCCatalog-Headers-WinStore10\WOCCatalog-Headers.vcxitems*{bef9b300-b97b-4e96-90ac-c7d0150a6ed7}*SharedItemsImports = 4 - WOCCatalog.vsimporter\WOCCatalog-Headers-WinStore10\WOCCatalog-Headers.vcxitems*{a74aae3b-53f9-42fe-b857-87153273da20}*SharedItemsImports = 9 + WOCCatalog.vsimporter\WOCCatalog-Headers-WinStore10\WOCCatalog-Headers.vcxitems*{6117D215-F749-41BD-834E-B5CC22B1784C}*SharedItemsImports = 9 + WOCCatalog.vsimporter\WOCCatalog-Headers-WinStore10\WOCCatalog-Headers.vcxitems*{7ACE16A9-EA45-422A-80C9-0783F0ED4E9C}*SharedItemsImports = 4 EndGlobalSection GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|ARM = Debug|ARM @@ -20,24 +20,24 @@ Global Release|Win32 = Release|Win32 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution - {BEF9B300-B97B-4E96-90AC-C7D0150A6ED7}.Debug|ARM.ActiveCfg = Debug|ARM - {BEF9B300-B97B-4E96-90AC-C7D0150A6ED7}.Debug|ARM.Build.0 = Debug|ARM - {BEF9B300-B97B-4E96-90AC-C7D0150A6ED7}.Debug|ARM.Deploy.0 = Debug|ARM - {BEF9B300-B97B-4E96-90AC-C7D0150A6ED7}.Debug|Win32.ActiveCfg = Debug|Win32 - {BEF9B300-B97B-4E96-90AC-C7D0150A6ED7}.Debug|Win32.Build.0 = Debug|Win32 - {BEF9B300-B97B-4E96-90AC-C7D0150A6ED7}.Debug|Win32.Deploy.0 = Debug|Win32 - {BEF9B300-B97B-4E96-90AC-C7D0150A6ED7}.Release|ARM.ActiveCfg = Release|ARM - {BEF9B300-B97B-4E96-90AC-C7D0150A6ED7}.Release|ARM.Build.0 = Release|ARM - {BEF9B300-B97B-4E96-90AC-C7D0150A6ED7}.Release|ARM.Deploy.0 = Release|ARM - {BEF9B300-B97B-4E96-90AC-C7D0150A6ED7}.Release|Win32.ActiveCfg = Release|Win32 - {BEF9B300-B97B-4E96-90AC-C7D0150A6ED7}.Release|Win32.Build.0 = Release|Win32 - {BEF9B300-B97B-4E96-90AC-C7D0150A6ED7}.Release|Win32.Deploy.0 = Release|Win32 + {7ACE16A9-EA45-422A-80C9-0783F0ED4E9C}.Debug|ARM.ActiveCfg = Debug|ARM + {7ACE16A9-EA45-422A-80C9-0783F0ED4E9C}.Debug|ARM.Build.0 = Debug|ARM + {7ACE16A9-EA45-422A-80C9-0783F0ED4E9C}.Debug|ARM.Deploy.0 = Debug|ARM + {7ACE16A9-EA45-422A-80C9-0783F0ED4E9C}.Debug|Win32.ActiveCfg = Debug|Win32 + {7ACE16A9-EA45-422A-80C9-0783F0ED4E9C}.Debug|Win32.Build.0 = Debug|Win32 + {7ACE16A9-EA45-422A-80C9-0783F0ED4E9C}.Debug|Win32.Deploy.0 = Debug|Win32 + {7ACE16A9-EA45-422A-80C9-0783F0ED4E9C}.Release|ARM.ActiveCfg = Release|ARM + {7ACE16A9-EA45-422A-80C9-0783F0ED4E9C}.Release|ARM.Build.0 = Release|ARM + {7ACE16A9-EA45-422A-80C9-0783F0ED4E9C}.Release|ARM.Deploy.0 = Release|ARM + {7ACE16A9-EA45-422A-80C9-0783F0ED4E9C}.Release|Win32.ActiveCfg = Release|Win32 + {7ACE16A9-EA45-422A-80C9-0783F0ED4E9C}.Release|Win32.Build.0 = Release|Win32 + {7ACE16A9-EA45-422A-80C9-0783F0ED4E9C}.Release|Win32.Deploy.0 = Release|Win32 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE EndGlobalSection GlobalSection(NestedProjects) = preSolution - {A74AAE3B-53F9-42FE-B857-87153273DA20} = {802EC330-1C66-4ECE-ACAC-A22F0058E869} - {BEF9B300-B97B-4E96-90AC-C7D0150A6ED7} = {802EC330-1C66-4ECE-ACAC-A22F0058E869} + {6117D215-F749-41BD-834E-B5CC22B1784C} = {B2E97B00-7169-4019-A43B-2BBEE8A27371} + {7ACE16A9-EA45-422A-80C9-0783F0ED4E9C} = {B2E97B00-7169-4019-A43B-2BBEE8A27371} EndGlobalSection EndGlobal diff --git a/samples/WOCCatalog/WOCCatalog.vsimporter/WOCCatalog-Headers-WinStore10/WOCCatalog-Headers.vcxitems b/samples/WOCCatalog/WOCCatalog.vsimporter/WOCCatalog-Headers-WinStore10/WOCCatalog-Headers.vcxitems index 8d8dbeec4f..1dfd91040a 100644 --- a/samples/WOCCatalog/WOCCatalog.vsimporter/WOCCatalog-Headers-WinStore10/WOCCatalog-Headers.vcxitems +++ b/samples/WOCCatalog/WOCCatalog.vsimporter/WOCCatalog-Headers-WinStore10/WOCCatalog-Headers.vcxitems @@ -1,44 +1,46 @@ - - - - true - WOCCatalog_Headers - $(MSBuildAllProjects);$(MSBuildThisFileFullPath) - {A74AAE3B-53F9-42FE-B857-87153273DA20} - {5E80FFAE-2B69-41C9-AA65-9B9570C93C27} - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file + + + + true + WOCCatalog_Headers + $(MSBuildAllProjects);$(MSBuildThisFileFullPath) + {6117D215-F749-41BD-834E-B5CC22B1784C} + {4EEA45CE-6497-4CB8-91E8-CA8E1AD18FEF} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/samples/WOCCatalog/WOCCatalog.vsimporter/WOCCatalog-Headers-WinStore10/WOCCatalog-Headers.vcxitems.filters b/samples/WOCCatalog/WOCCatalog.vsimporter/WOCCatalog-Headers-WinStore10/WOCCatalog-Headers.vcxitems.filters index 549abc77b2..cfcc08fcdc 100644 --- a/samples/WOCCatalog/WOCCatalog.vsimporter/WOCCatalog-Headers-WinStore10/WOCCatalog-Headers.vcxitems.filters +++ b/samples/WOCCatalog/WOCCatalog.vsimporter/WOCCatalog-Headers-WinStore10/WOCCatalog-Headers.vcxitems.filters @@ -1,97 +1,103 @@ - - - - - {6C513927-611F-4A04-ACA2-893303ABF0CA} - - - - - WOCCatalog - - - WOCCatalog - - - WOCCatalog - - - WOCCatalog - - - WOCCatalog - - - WOCCatalog - - - WOCCatalog - - - WOCCatalog - - - WOCCatalog - - - WOCCatalog - - - WOCCatalog - - - WOCCatalog - - - WOCCatalog - - - WOCCatalog - - - WOCCatalog - - - WOCCatalog - - - WOCCatalog - - - WOCCatalog - - - WOCCatalog - - - WOCCatalog - - - WOCCatalog - - - WOCCatalog - - - WOCCatalog - - - WOCCatalog - - - WOCCatalog - - - WOCCatalog - - - WOCCatalog - - - WOCCatalog - - - WOCCatalog - - - \ No newline at end of file + + + + + {90485838-95F1-459D-87E4-92788E02C934} + + + + + WOCCatalog + + + WOCCatalog + + + WOCCatalog + + + WOCCatalog + + + WOCCatalog + + + WOCCatalog + + + WOCCatalog + + + WOCCatalog + + + WOCCatalog + + + WOCCatalog + + + WOCCatalog + + + WOCCatalog + + + WOCCatalog + + + WOCCatalog + + + WOCCatalog + + + WOCCatalog + + + WOCCatalog + + + WOCCatalog + + + WOCCatalog + + + WOCCatalog + + + WOCCatalog + + + WOCCatalog + + + WOCCatalog + + + WOCCatalog + + + WOCCatalog + + + WOCCatalog + + + WOCCatalog + + + WOCCatalog + + + WOCCatalog + + + WOCCatalog + + + WOCCatalog + + + diff --git a/samples/WOCCatalog/WOCCatalog.vsimporter/WOCCatalog-WinStore10/WOCCatalog-Debug-xcvars.txt b/samples/WOCCatalog/WOCCatalog.vsimporter/WOCCatalog-WinStore10/WOCCatalog-Debug-xcvars.txt index 0f64203c0e..84bed99c58 100644 --- a/samples/WOCCatalog/WOCCatalog.vsimporter/WOCCatalog-WinStore10/WOCCatalog-Debug-xcvars.txt +++ b/samples/WOCCatalog/WOCCatalog.vsimporter/WOCCatalog-WinStore10/WOCCatalog-Debug-xcvars.txt @@ -154,4 +154,4 @@ VSIMPORTER_TEMPLATES_DIR = C:\Main\new\bin/../msvc/vsimporter-templates WARNING_CFLAGS = WARNING_LDFLAGS = WINOBJC_SDK_ROOT = C:\Main\new\bin/.. -windir = C:\windows +windir = C:\windows \ No newline at end of file diff --git a/samples/WOCCatalog/WOCCatalog.vsimporter/WOCCatalog-WinStore10/WOCCatalog-Release-xcvars.txt b/samples/WOCCatalog/WOCCatalog.vsimporter/WOCCatalog-WinStore10/WOCCatalog-Release-xcvars.txt index f21bc0cd3e..7f68a212f8 100644 --- a/samples/WOCCatalog/WOCCatalog.vsimporter/WOCCatalog-WinStore10/WOCCatalog-Release-xcvars.txt +++ b/samples/WOCCatalog/WOCCatalog.vsimporter/WOCCatalog-WinStore10/WOCCatalog-Release-xcvars.txt @@ -154,4 +154,4 @@ VSIMPORTER_TEMPLATES_DIR = C:\Main\new\bin/../msvc/vsimporter-templates WARNING_CFLAGS = WARNING_LDFLAGS = WINOBJC_SDK_ROOT = C:\Main\new\bin/.. -windir = C:\windows +windir = C:\windows \ No newline at end of file diff --git a/samples/WOCCatalog/WOCCatalog.vsimporter/WOCCatalog-WinStore10/WOCCatalog.vcxproj b/samples/WOCCatalog/WOCCatalog.vsimporter/WOCCatalog-WinStore10/WOCCatalog.vcxproj index 7b5943dda1..68771e422b 100644 --- a/samples/WOCCatalog/WOCCatalog.vsimporter/WOCCatalog-WinStore10/WOCCatalog.vcxproj +++ b/samples/WOCCatalog/WOCCatalog.vsimporter/WOCCatalog-WinStore10/WOCCatalog.vcxproj @@ -1,241 +1,245 @@ - - - - - Debug - ARM - - - Debug - Win32 - - - Release - ARM - - - Release - Win32 - - - - WOCCatalog - WOCCatalog - en-US - 14.0 - true - Windows Store - 10.0 - true - 10.0.10586.0 - 10.0.10240.0 - {BEF9B300-B97B-4E96-90AC-C7D0150A6ED7} - ..\..\..\.. - - - - Application - v140 - WOCCatalog - - - Application - v140 - WOCCatalog - - - Application - v140 - true - true - WOCCatalog - - - Application - v140 - true - true - WOCCatalog - - - - - - - - - - - - - - - - - - - - - - - WOCCatalog_TemporaryKey.pfx - - - - /bigobj %(AdditionalOptions) - 4453;28204 - MultiThreadedDebugDLL - - - MultiThreadedDebugDLL - Project - true - Disabled - DEBUG=1 - - - true - %(AdditionalDependencies);GLKit.lib;OpenGLES.lib - - - true - - - - - /bigobj %(AdditionalOptions) - 4453;28204 - MultiThreadedDebugDLL - - - MultiThreadedDebugDLL - Project - true - Disabled - DEBUG=1 - - - true - %(AdditionalDependencies);GLKit.lib;OpenGLES.lib - - - true - - - - - /bigobj %(AdditionalOptions) - 4453;28204 - - - Project - true - MinSpace - - - true - %(AdditionalDependencies);GLKit.lib;OpenGLES.lib - - - true - - - - - /bigobj %(AdditionalOptions) - 4453;28204 - - - Project - true - MinSpace - - - true - %(AdditionalDependencies);GLKit.lib;OpenGLES.lib - - - true - - - - - Designer - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - false - false - WOCCatalog-Debug-xcvars.txt - WOCCatalog-Release-xcvars.txt - - - false - - - false - - - - - - - - \ No newline at end of file + + + + + Debug + ARM + + + Debug + Win32 + + + Release + ARM + + + Release + Win32 + + + + WOCCatalog + WOCCatalog + en-US + 14.0 + true + Windows Store + 10.0 + true + 10.0.10586.0 + 10.0.10240.0 + {7ACE16A9-EA45-422A-80C9-0783F0ED4E9C} + ..\..\..\.. + + + + Application + v140 + WOCCatalog + + + Application + v140 + WOCCatalog + + + Application + v140 + true + true + WOCCatalog + + + Application + v140 + true + true + WOCCatalog + + + + + + + + + + + + + + + + + + + + + + + WOCCatalog_TemporaryKey.pfx + + + + /bigobj %(AdditionalOptions) + 4453;28204 + MultiThreadedDebugDLL + + + MultiThreadedDebugDLL + Project + true + true + Disabled + DEBUG=1 + + + true + %(AdditionalDependencies);Accelerate.lib;GLKit.lib;OpenGLES.lib + + + true + + + + + /bigobj %(AdditionalOptions) + 4453;28204 + MultiThreadedDebugDLL + + + MultiThreadedDebugDLL + Project + true + true + Disabled + DEBUG=1 + + + true + %(AdditionalDependencies);Accelerate.lib;GLKit.lib;OpenGLES.lib + + + true + + + + + /bigobj %(AdditionalOptions) + 4453;28204 + + + Project + true + true + MinSpace + + + true + %(AdditionalDependencies);Accelerate.lib;GLKit.lib;OpenGLES.lib + + + true + + + + + /bigobj %(AdditionalOptions) + 4453;28204 + + + Project + true + true + MinSpace + + + true + %(AdditionalDependencies);Accelerate.lib;GLKit.lib;OpenGLES.lib + + + true + + + + + Designer + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + false + false + WOCCatalog-Debug-xcvars.txt + WOCCatalog-Release-xcvars.txt + + + false + + + false + + + + + + + + diff --git a/samples/WOCCatalog/WOCCatalog.vsimporter/WOCCatalog-WinStore10/WOCCatalog.vcxproj.filters b/samples/WOCCatalog/WOCCatalog.vsimporter/WOCCatalog-WinStore10/WOCCatalog.vcxproj.filters index 2c0cd61cb9..08407f4304 100644 --- a/samples/WOCCatalog/WOCCatalog.vsimporter/WOCCatalog-WinStore10/WOCCatalog.vcxproj.filters +++ b/samples/WOCCatalog/WOCCatalog.vsimporter/WOCCatalog-WinStore10/WOCCatalog.vcxproj.filters @@ -1,214 +1,206 @@ - - - - - {1872bc2a-34a4-4c18-985e-08698eb76a1e} - - - {55369852-fa74-4fd0-823c-388d429288f9} - - - {82FAEF38-368D-41D3-A499-6503680C36FF} - - - {7BC6BF3D-07D9-43F9-94BF-237C32EDD4BA} - - - {E63D155B-A987-4761-97E9-15786054F904} - - - {A2B40BA5-E2DE-4CB5-9F6F-52F8F5AAD9C8} - - - - - Assets - - - Assets - - - Assets - - - Assets - - - Assets - - - Assets - - - Assets - - - WOCCatalog - - - WOCCatalog - - - WOCCatalog - - - WOCCatalog - - - WOCCatalog - - - WOCCatalog - - - WOCCatalog - - - WOCCatalog\Supporting Files - - - WOCCatalog - - - WOCCatalog - - - WOCCatalog - - - WOCCatalog - - - WOCCatalog - - - WOCCatalog - - - WOCCatalog - - - WOCCatalog - - - WOCCatalog - - - WOCCatalog - - - WOCCatalog - - - WOCCatalog - - - WOCCatalog - - - WOCCatalog - - - WOCCatalog - - - WOCCatalog - - - WOCCatalog - - - WOCCatalog - - - WOCCatalog - - - WOCCatalog - - - WOCCatalog - - - Images - - - WOCCatalog - - - Images - - - Images - - - Images - - - Images - - - Images - - - Images - - - Images - - - Images - - - Images - - - Images - - - Images - - - Images - - - Images - - - Images - - - - Xcode Variable Files - - - Xcode Variable Files - - - Images - - - - - - - - - - - WOCCatalog - - - WOCCatalog - - - WOCCatalog - - - WOCCatalog - - - - - - \ No newline at end of file + + + + + {1567d142-5fbf-4776-a7d3-b4abe59fa011} + + + {0aacdb63-f52f-443a-9f3c-874c96e73823} + + + {BDADC132-BB81-4590-A5AB-41077A855D59} + + + {5C0413A9-63B8-4284-B0D2-17F8F42B1AC2} + + + {C928C0ED-D750-4B98-8BAF-4833E09C1833} + + + {4B384EFB-A1AE-4CC2-8BB5-7873041750D9} + + + + + Assets + + + Assets + + + Assets + + + Assets + + + Assets + + + Assets + + + Assets + + + WOCCatalog + + + WOCCatalog + + + WOCCatalog + + + WOCCatalog + + + WOCCatalog + + + WOCCatalog + + + WOCCatalog + + + WOCCatalog\Supporting Files + + + WOCCatalog + + + WOCCatalog + + + WOCCatalog + + + WOCCatalog + + + WOCCatalog + + + WOCCatalog + + + WOCCatalog + + + WOCCatalog + + + WOCCatalog + + + WOCCatalog + + + WOCCatalog + + + WOCCatalog + + + WOCCatalog + + + WOCCatalog + + + WOCCatalog + + + WOCCatalog + + + WOCCatalog + + + WOCCatalog + + + WOCCatalog + + + WOCCatalog + + + WOCCatalog + + + WOCCatalog + + + WOCCatalog + + + WOCCatalog + + + Images + + + Images + + + WOCCatalog + + + Images + + + Images + + + Images + + + Images + + + Images + + + Images + + + Images + + + Images + + + Images + + + Images + + + Images + + + Images + + + Images + + + Images + + + + Xcode Variable Files + + + Xcode Variable Files + + + + + + + + + diff --git a/samples/WOCCatalog/WOCCatalog.xcodeproj/project.pbxproj b/samples/WOCCatalog/WOCCatalog.xcodeproj/project.pbxproj index 5ca32963d9..b3883a135c 100644 --- a/samples/WOCCatalog/WOCCatalog.xcodeproj/project.pbxproj +++ b/samples/WOCCatalog/WOCCatalog.xcodeproj/project.pbxproj @@ -50,6 +50,8 @@ 7BCEEE4D1B70220300C31CF5 /* OpenGLES20Controller.m in Sources */ = {isa = PBXBuildFile; fileRef = 7BCEEE4A1B70220300C31CF5 /* OpenGLES20Controller.m */; }; 7BCEEE4F1B70225500C31CF5 /* OpenGLES.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 7BCEEE4E1B70225500C31CF5 /* OpenGLES.framework */; }; 8430AAC91BE7F2E500927545 /* GLKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 8430AAC81BE7F2E500927545 /* GLKit.framework */; }; + C14942D11C77E1A700C2B67E /* Accelerate.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C14942D01C77E1A700C2B67E /* Accelerate.framework */; }; + C14942D41C77E1EE00C2B67E /* AccelerateViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = C14942D31C77E1EE00C2B67E /* AccelerateViewController.m */; }; D2AC20301C6972A600D54717 /* BasicAnimationViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = D2AC202F1C6972A600D54717 /* BasicAnimationViewController.m */; }; D2AC20341C69733600D54717 /* photo9.jpg in Resources */ = {isa = PBXBuildFile; fileRef = D2AC20331C69733600D54717 /* photo9.jpg */; }; D2AC20361C69734F00D54717 /* photo10.jpg in Resources */ = {isa = PBXBuildFile; fileRef = D2AC20351C69734F00D54717 /* photo10.jpg */; }; @@ -143,6 +145,9 @@ 7BCEEE4A1B70220300C31CF5 /* OpenGLES20Controller.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OpenGLES20Controller.m; sourceTree = ""; }; 7BCEEE4E1B70225500C31CF5 /* OpenGLES.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = OpenGLES.framework; path = System/Library/Frameworks/OpenGLES.framework; sourceTree = SDKROOT; }; 8430AAC81BE7F2E500927545 /* GLKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = GLKit.framework; path = System/Library/Frameworks/GLKit.framework; sourceTree = SDKROOT; }; + C14942D01C77E1A700C2B67E /* Accelerate.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Accelerate.framework; path = System/Library/Frameworks/Accelerate.framework; sourceTree = SDKROOT; }; + C14942D21C77E1EE00C2B67E /* AccelerateViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AccelerateViewController.h; sourceTree = ""; }; + C14942D31C77E1EE00C2B67E /* AccelerateViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AccelerateViewController.m; sourceTree = ""; }; D2AC202E1C69729C00D54717 /* BasicAnimationViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BasicAnimationViewController.h; sourceTree = ""; }; D2AC202F1C6972A600D54717 /* BasicAnimationViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = BasicAnimationViewController.m; sourceTree = ""; }; D2AC20331C69733600D54717 /* photo9.jpg */ = {isa = PBXFileReference; lastKnownFileType = image.jpeg; name = photo9.jpg; path = WOCCatalog/Images/photo9.jpg; sourceTree = ""; }; @@ -163,6 +168,7 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( + C14942D11C77E1A700C2B67E /* Accelerate.framework in Frameworks */, 8430AAC91BE7F2E500927545 /* GLKit.framework in Frameworks */, 7BCEEE4F1B70225500C31CF5 /* OpenGLES.framework in Frameworks */, ); @@ -181,6 +187,7 @@ 4EE8614C1B5996BF00682BDB = { isa = PBXGroup; children = ( + C14942D01C77E1A700C2B67E /* Accelerate.framework */, 8430AAC81BE7F2E500927545 /* GLKit.framework */, 7BCEEE4E1B70225500C31CF5 /* OpenGLES.framework */, 4EE8617E1B5996DA00682BDB /* Images */, @@ -202,6 +209,8 @@ 4EE861571B5996BF00682BDB /* WOCCatalog */ = { isa = PBXGroup; children = ( + C14942D21C77E1EE00C2B67E /* AccelerateViewController.h */, + C14942D31C77E1EE00C2B67E /* AccelerateViewController.m */, D2AC202F1C6972A600D54717 /* BasicAnimationViewController.m */, D2AC202E1C69729C00D54717 /* BasicAnimationViewController.h */, 49FF82D01C18BFF700798804 /* ApplicationViewController.h */, @@ -460,6 +469,7 @@ 4EE861FA1B5997E400682BDB /* ImagesViewController.m in Sources */, F01C225B1C1A54450007FF0B /* TaskInfoViewController.m in Sources */, 4EE861D91B5997A500682BDB /* ToolbarsViewController.m in Sources */, + C14942D41C77E1EE00C2B67E /* AccelerateViewController.m in Sources */, 4EE861D71B5997A500682BDB /* TextFieldsViewController.m in Sources */, 4EE861D41B5997A500682BDB /* PickersViewController.m in Sources */, ); diff --git a/samples/WOCCatalog/WOCCatalog/AccelerateViewController.h b/samples/WOCCatalog/WOCCatalog/AccelerateViewController.h new file mode 100644 index 0000000000..9873992a07 --- /dev/null +++ b/samples/WOCCatalog/WOCCatalog/AccelerateViewController.h @@ -0,0 +1,22 @@ +//****************************************************************************** +// +// Copyright (c) 2015 Microsoft Corporation. All rights reserved. +// +// This code is licensed under the MIT License (MIT). +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +// +//****************************************************************************** + +#import +#import + +@interface AccelerateViewController : UITableViewController + +@end \ No newline at end of file diff --git a/samples/WOCCatalog/WOCCatalog/AccelerateViewController.m b/samples/WOCCatalog/WOCCatalog/AccelerateViewController.m new file mode 100644 index 0000000000..85199d7d74 --- /dev/null +++ b/samples/WOCCatalog/WOCCatalog/AccelerateViewController.m @@ -0,0 +1,375 @@ +//****************************************************************************** +// +// Copyright (c) 2015 Microsoft Corporation. All rights reserved. +// +// This code is licensed under the MIT License (MIT). +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +// +//****************************************************************************** + +#import "AccelerateViewController.h" +#import "SingleImageViewController.h" + +@implementation AccelerateViewController + +int accelerateImageNumber = 1; +int valueRed = 100, valueGreen = 100, valueBlue = 100; +int convolveSize = 1; +NSArray *indexPathArray; +UIImage *img; +UIImageView *imv; +UISlider* redSlider; +UISlider* greenSlider; +UISlider* blueSlider; +UISlider* convolveSlider; +UILabel *rLabel, *gLabel, *bLabel, *boxLabel; + +- (void)viewDidLoad { + [super viewDidLoad]; + + redSlider = [[UISlider alloc] initWithFrame:CGRectMake(5.0, 12.0, 180.0, 8.0)]; + redSlider.backgroundColor = [UIColor clearColor]; + redSlider.minimumValue = 0.0; + redSlider.maximumValue = 200.0; + redSlider.continuous = YES; + redSlider.value = 100.0; + + greenSlider = [[UISlider alloc] initWithFrame:CGRectMake(5.0, 12.0, 180.0, 8.0)]; + greenSlider.backgroundColor = [UIColor clearColor]; + greenSlider.minimumValue = 0.0; + greenSlider.maximumValue = 200.0; + greenSlider.continuous = YES; + greenSlider.value = 100.0; + + blueSlider = [[UISlider alloc] initWithFrame:CGRectMake(5.0, 12.0, 180.0, 8.0)]; + blueSlider.backgroundColor = [UIColor clearColor]; + blueSlider.minimumValue = 0.0; + blueSlider.maximumValue = 200.0; + blueSlider.continuous = YES; + blueSlider.value = 100.0; + + convolveSlider = [[UISlider alloc] initWithFrame:CGRectMake(5.0, 12.0, 180.0, 8.0)]; + convolveSlider.backgroundColor = [UIColor clearColor]; + convolveSlider.minimumValue = 1.0; + convolveSlider.maximumValue = 99.0; + convolveSlider.continuous = YES; + convolveSlider.value = 1.0; + + [redSlider addTarget:self action:@selector(redChanged:) forControlEvents:UIControlEventValueChanged]; + [greenSlider addTarget:self action:@selector(greenChanged:) forControlEvents:UIControlEventValueChanged]; + [blueSlider addTarget:self action:@selector(blueChanged:) forControlEvents:UIControlEventValueChanged]; + [convolveSlider addTarget:self action:@selector(convolveChanged:) forControlEvents:UIControlEventValueChanged]; + + rLabel = [[UILabel alloc] init]; + gLabel = [[UILabel alloc] init]; + bLabel = [[UILabel alloc] init]; + boxLabel = [[UILabel alloc] init]; + + img = [UIImage imageNamed:[NSString stringWithFormat:@"photo%d.jpg", accelerateImageNumber]]; +} + +- (NSInteger)tableView:(UITableView*)tableView numberOfRowsInSection:(NSInteger)section { + return 8; +} + +- (CGFloat)tableView:(UITableView*)tableView heightForRowAtIndexPath:(NSIndexPath*)indexPath { + CGRect screenRect = [[UIScreen mainScreen] bounds]; + if (indexPath.row == 1) + return screenRect.size.height - 360; + return 40; +} + +- (UITableViewCell*)tableView:(UITableView*)tableView cellForRowAtIndexPath:(NSIndexPath*)indexPath { + UITableViewCell* cell = [tableView dequeueReusableCellWithIdentifier:@"MenuCell"]; + if (nil == cell) { + cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:@"MenuCell"]; + } + + if (indexPath.row == 0) { + // Title cell + + cell.textLabel.text = @"Accelerate Test"; + cell.selectionStyle = UITableViewCellSelectionStyleNone; + } else if (indexPath.row == 1) { + // Image display box + + [imv removeFromSuperview]; + UIImage *transformImg = [self transformImage:img]; + imv = [[UIImageView alloc] initWithFrame:CGRectMake(3, 2, cell.bounds.size.width - 6.0f, cell.bounds.size.height - 4.0f)]; + imv.image = transformImg; + + [imv setAutoresizingMask:UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight]; + [cell addSubview:imv]; + + cell.selectionStyle = UITableViewCellSelectionStyleNone; + } else if (indexPath.row == 2) { + // Red controls + + /*UIButton *rDown = [UIButton buttonWithType:UIButtonTypeRoundedRect]; + rDown.frame = CGRectMake(cell.bounds.size.width - 70.0f, 5.0f, 30.0f, cell.bounds.size.height - 15.0f); + rDown.layer.cornerRadius = 5.0f; + rDown.backgroundColor = [UIColor lightGrayColor]; + [rDown setTitleColor:[UIColor blackColor] forState:UIControlStateNormal]; + [rDown setTitle:@"-" forState:UIControlStateNormal]; + [rDown setAutoresizingMask:UIViewAutoresizingFlexibleLeftMargin]; + + UIButton *rUp = [UIButton buttonWithType:UIButtonTypeRoundedRect]; + rUp.frame = CGRectMake(cell.bounds.size.width - 35.0f, 5.0f, 30.0f, cell.bounds.size.height - 15.0f); + rUp.layer.cornerRadius = 5.0f; + rUp.backgroundColor = [UIColor lightGrayColor]; + [rUp setTitleColor:[UIColor blackColor] forState:UIControlStateNormal]; + [rUp setTitle:@"+" forState:UIControlStateNormal]; + [rUp setAutoresizingMask:UIViewAutoresizingFlexibleLeftMargin]; + + [cell addSubview:rDown]; + [cell addSubview:rUp]; + */ + + //cell.textLabel.text = [NSString stringWithFormat:@"Red: %d%%", valueRed]; + cell.textLabel.text = [NSString stringWithFormat:@"Red"]; + cell.selectionStyle = UITableViewCellSelectionStyleNone; + + cell.accessoryView = redSlider; + + //[redSlider addTarget:self action:@selector(redChanged:) forControlEvents:UIControlEventValueChanged]; + + //[rUp addTarget:self action:@selector(rUpPress) forControlEvents:UIControlEventTouchUpInside]; + //[rDown addTarget:self action:@selector(rDownPress) forControlEvents:UIControlEventTouchUpInside]; + } else if (indexPath.row == 3) { + // Green controls + + cell.textLabel.text = [NSString stringWithFormat:@"Green"]; + cell.selectionStyle = UITableViewCellSelectionStyleNone; + + cell.accessoryView = greenSlider; + } else if (indexPath.row == 4) { + // Blue controls + + cell.textLabel.text = [NSString stringWithFormat:@"Blue"]; + cell.selectionStyle = UITableViewCellSelectionStyleNone; + + cell.accessoryView = blueSlider; + } else if (indexPath.row == 5) { + // Box convolve controls + + cell.textLabel.text = [NSString stringWithFormat:@"Blur"]; + cell.selectionStyle = UITableViewCellSelectionStyleNone; + + cell.accessoryView = convolveSlider; + } else if (indexPath.row == 6) { + // Labels + + [rLabel removeFromSuperview]; + [gLabel removeFromSuperview]; + [bLabel removeFromSuperview]; + [boxLabel removeFromSuperview]; + + rLabel.text = [NSString stringWithFormat:@"R: %d%%", valueRed]; + gLabel.text = [NSString stringWithFormat:@"G: %d%%", valueGreen]; + bLabel.text = [NSString stringWithFormat:@"B: %d%%", valueBlue]; + boxLabel.text = [NSString stringWithFormat:@"Kernel Size: %d", convolveSize]; + + rLabel.frame = CGRectMake(17.0f, 5.0f, 100.0f, cell.bounds.size.height - 5.0f); + gLabel.frame = CGRectMake(92.0f, 5.0f, 100.0f, cell.bounds.size.height - 5.0f); + bLabel.frame = CGRectMake(167.0f, 5.0f, 100.0f, cell.bounds.size.height - 5.0f); + boxLabel.frame = CGRectMake(242.0f, 5.0f, 200.0f, cell.bounds.size.height - 5.0f); + + [rLabel setAutoresizingMask:UIViewAutoresizingFlexibleHeight]; + [gLabel setAutoresizingMask:UIViewAutoresizingFlexibleHeight]; + [bLabel setAutoresizingMask:UIViewAutoresizingFlexibleHeight]; + [boxLabel setAutoresizingMask:UIViewAutoresizingFlexibleHeight]; + + [cell addSubview:rLabel]; + [cell addSubview:gLabel]; + [cell addSubview:bLabel]; + [cell addSubview:boxLabel]; + + } else if (indexPath.row == 7) { + // Image change + + UIButton *imageChange = [UIButton buttonWithType:UIButtonTypeRoundedRect]; + imageChange.frame = CGRectMake(10.0f, 5.0f, 120.0f, cell.bounds.size.height - 15.0f); + imageChange.layer.cornerRadius = 5.0f; + imageChange.backgroundColor = [UIColor lightGrayColor]; + [imageChange setTitleColor:[UIColor blackColor] forState:UIControlStateNormal]; + [imageChange setTitle:@"Next Image" forState:UIControlStateNormal]; + + [cell addSubview:imageChange]; + + [imageChange addTarget:self action:@selector(imageChangePress) forControlEvents:UIControlEventTouchUpInside]; + cell.selectionStyle = UITableViewCellSelectionStyleNone; + } + + return cell; +} + +-(void) redChanged:(UISlider *)slider { + int oldValue = valueRed; + valueRed = (int) slider.value; + + if (oldValue != valueRed) { + indexPathArray = [NSArray arrayWithObject:[NSIndexPath indexPathForRow:1 inSection:0]]; + [self.tableView reloadRowsAtIndexPaths:indexPathArray withRowAnimation:UITableViewRowAnimationNone]; + + indexPathArray = [NSArray arrayWithObject:[NSIndexPath indexPathForRow:6 inSection:0]]; + [self.tableView reloadRowsAtIndexPaths:indexPathArray withRowAnimation:UITableViewRowAnimationNone]; + } +} + +-(void) blueChanged:(UISlider *)slider { + int oldValue = valueBlue; + valueBlue = (int) slider.value; + + if (oldValue != valueBlue) { + indexPathArray = [NSArray arrayWithObject:[NSIndexPath indexPathForRow:1 inSection:0]]; + [self.tableView reloadRowsAtIndexPaths:indexPathArray withRowAnimation:UITableViewRowAnimationNone]; + + indexPathArray = [NSArray arrayWithObject:[NSIndexPath indexPathForRow:6 inSection:0]]; + [self.tableView reloadRowsAtIndexPaths:indexPathArray withRowAnimation:UITableViewRowAnimationNone]; + } +} + +-(void) greenChanged:(UISlider *)slider { + int oldValue = valueGreen; + valueGreen = (int) slider.value; + + if (oldValue != valueGreen) { + indexPathArray = [NSArray arrayWithObject:[NSIndexPath indexPathForRow:1 inSection:0]]; + [self.tableView reloadRowsAtIndexPaths:indexPathArray withRowAnimation:UITableViewRowAnimationNone]; + + indexPathArray = [NSArray arrayWithObject:[NSIndexPath indexPathForRow:6 inSection:0]]; + [self.tableView reloadRowsAtIndexPaths:indexPathArray withRowAnimation:UITableViewRowAnimationNone]; + } +} + +-(void) convolveChanged:(UISlider *)slider { + int oldValue = convolveSize; + convolveSize = (int) slider.value; + convolveSize += (convolveSize % 2) - 1; + + if (oldValue != convolveSize) { + indexPathArray = [NSArray arrayWithObject:[NSIndexPath indexPathForRow:1 inSection:0]]; + [self.tableView reloadRowsAtIndexPaths:indexPathArray withRowAnimation:UITableViewRowAnimationNone]; + + indexPathArray = [NSArray arrayWithObject:[NSIndexPath indexPathForRow:6 inSection:0]]; + [self.tableView reloadRowsAtIndexPaths:indexPathArray withRowAnimation:UITableViewRowAnimationNone]; + } +} + + +-(void) imageChangePress +{ + accelerateImageNumber++; + if (accelerateImageNumber == 7) + accelerateImageNumber = 1; + + img = [UIImage imageNamed:[NSString stringWithFormat:@"photo%d.jpg", accelerateImageNumber]]; + + indexPathArray = [NSArray arrayWithObject:[NSIndexPath indexPathForRow:1 inSection:0]]; + [self.tableView reloadRowsAtIndexPaths:indexPathArray withRowAnimation:UITableViewRowAnimationNone]; + + indexPathArray = [NSArray arrayWithObject:[NSIndexPath indexPathForRow:6 inSection:0]]; + [self.tableView reloadRowsAtIndexPaths:indexPathArray withRowAnimation:UITableViewRowAnimationNone]; +} + +-(UIImage *)transformImage:(UIImage *)image { + CGImageRef img = image.CGImage; + + vImage_Buffer inBuffer, midBuffer, outBuffer; + vImage_Error error; + void *pixelBuffer, *midPixelBuffer; + + //create vImage_Buffer with data from CGImageRef + + CGDataProviderRef inProvider = CGImageGetDataProvider(img); + CFDataRef inBitmapData = CGDataProviderCopyData(inProvider); + + inBuffer.width = CGImageGetWidth(img); + inBuffer.height = CGImageGetHeight(img); + inBuffer.rowBytes = CGImageGetBytesPerRow(img); + + inBuffer.data = (void*)CFDataGetBytePtr(inBitmapData); + + //create vImage_Buffer for output + + midPixelBuffer = malloc(CGImageGetBytesPerRow(img) * CGImageGetHeight(img)); + pixelBuffer = malloc(CGImageGetBytesPerRow(img) * CGImageGetHeight(img)); + + if(midPixelBuffer == NULL) + NSLog(@"No midpixelbuffer"); + if(pixelBuffer == NULL) + NSLog(@"No pixelbuffer"); + + midBuffer.data = midPixelBuffer; + midBuffer.width = CGImageGetWidth(img); + midBuffer.height = CGImageGetHeight(img); + midBuffer.rowBytes = CGImageGetBytesPerRow(img); + + outBuffer.data = pixelBuffer; + outBuffer.width = CGImageGetWidth(img); + outBuffer.height = CGImageGetHeight(img); + outBuffer.rowBytes = CGImageGetBytesPerRow(img); + + int16_t A[] = { valueRed, 0, 0, 0, + 0, valueGreen, 0, 0, + 0, 0, valueBlue, 0, + 0, 0, 0, 0 }; + + double meandivisor = 100; + + error = vImageMatrixMultiply_ARGB8888(&inBuffer, &midBuffer, A, meandivisor, NULL, NULL, 0); + + if (error) { + NSLog(@"error from matrix multiply %ld", error); + } + + Pixel_8888 background; + background[0] = 0; + background[1] = 0; + background[2] = 0; + background[3] = 0; + + //perform convolution + error = vImageBoxConvolve_ARGB8888(&midBuffer, &outBuffer, NULL, 0, 0, convolveSize, convolveSize, background, kvImageEdgeExtend); + + if (error) { + NSLog(@"error from convolution %ld", error); + } + + //create CGImageRef from vImage_Buffer output + //1 - CGBitmapContextCreateImage - + + CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB(); + + CGContextRef ctx = CGBitmapContextCreate(outBuffer.data, + outBuffer.width, + outBuffer.height, + 8, + outBuffer.rowBytes, + colorSpace, + (CGBitmapInfo)kCGImageAlphaNoneSkipLast); + CGImageRef imageRef = CGBitmapContextCreateImage (ctx); + + UIImage *returnImage = [UIImage imageWithCGImage:imageRef]; + + //clean up + CGContextRelease(ctx); + CGColorSpaceRelease(colorSpace); + free(midPixelBuffer); + free(pixelBuffer); + CFRelease(inBitmapData); + CGImageRelease(imageRef); + + return returnImage; + +} + +@end + diff --git a/samples/WOCCatalog/WOCCatalog/MainViewController.m b/samples/WOCCatalog/WOCCatalog/MainViewController.m index 7b107ce55b..09831e4b06 100644 --- a/samples/WOCCatalog/WOCCatalog/MainViewController.m +++ b/samples/WOCCatalog/WOCCatalog/MainViewController.m @@ -37,6 +37,7 @@ #import "ApplicationViewController.h" #import "FoundationsViewController.h" #import "BasicAnimationViewController.h" +#import "AccelerateViewController.h" #ifdef WINOBJC #import "XamlViewController.h" @@ -120,6 +121,9 @@ - (void)viewDidLoad { // Basic Animation [self addMenuItemViewController:[[BasicAnimationViewController alloc] init] andTitle:@"Animation"]; + + // Accelerate + [self addMenuItemViewController:[[AccelerateViewController alloc] init] andTitle:@"Accelerate"]; } - (void)didReceiveMemoryWarning { diff --git a/tests/unittests/Accelerate/vDSPTest.mm b/tests/unittests/Accelerate/vDSPTest.mm index d4d2a87868..1599cc1835 100644 --- a/tests/unittests/Accelerate/vDSPTest.mm +++ b/tests/unittests/Accelerate/vDSPTest.mm @@ -187,9 +187,7 @@ static void vDSPInit(void) { // Template for checking NAN values in floating points, not included in tests for BLAS as not needed // Returns a true if either the expected value or the result are NAN, because we do not wish to compare NAN to anything // If one value is NAN but not the other, throw the issue but do not terminate the function -template -bool fail_nan_test(const T &result, const T &expected) -{ +template bool fail_nan_test(const T &result, const T &expected) { if (isnan(expected)) { if (isnan(result)) { return true; @@ -764,4 +762,250 @@ static void checkArrayDouble(double* result, double* expected, int size, char* n checkArrayDouble(zArrayC->imagp, zvmovD_exp_imag, lengthN, "zvmovD_imag"); } +//Test for validating the single-precision real-to-complex DFT for a vector +TEST(Accelerate, vDSP_DFT_RealToComplex_Float) { + vDSP_DFT_Setup zrop_Setup = vDSP_DFT_zrop_CreateSetup(NULL, 8, vDSP_DFT_FORWARD); + ASSERT_TRUE_MSG(zrop_Setup != nullptr, "FAILED: vDSP_zop_CreateSetup failed!\n"); + + //Scenario 1 + float RealIn1[] = {5, 10, 15, 20}; + float RealIn2[] = {2, -4, 9, -12}; + float RealOut1 [8] = {0}; + float ImgOut1[8] = {0}; + + vDSP_DFT_Execute(zrop_Setup, RealIn1, RealIn2, RealOut1, ImgOut1); + + float DFT_exp_real1[] = {90.000000, -41.213204, -20.000000, 1.213204, 0.000000, 0.000000, 0.000000, 0.000000}; + float DFT_exp_imag1[] = {110.000000, 18.585786, -54.000000, -21.414214, 0.000000, 0.000000, 0.000000, 0.000000}; + + checkArraySingle(RealOut1, DFT_exp_real1, 8, "DFT_RtoC_Real_S1"); + checkArraySingle(ImgOut1, DFT_exp_imag1, 8, "DFT_RtoC_Imag_S1"); + + //Scenario 2 + float RealIn3[] = {1, 3, 5, 7}; + float RealIn4[] = {2, 4, 6, 8}; + + vDSP_DFT_Execute(zrop_Setup, RealIn3, RealIn4, RealOut1, ImgOut1); + + float DFT_exp_real2[] = {72.000000, -8.000000, -8.000000, -8.000000, 0.000000, 0.000000, 0.000000, 0.000000}; + float DFT_exp_imag2[] = {-8.000000, 19.313709, 8.000000, 3.313708, 0.000000, 0.000000, 0.000000, 0.000000}; + + checkArraySingle(RealOut1, DFT_exp_real2, 8, "DFT_RtoC_Real_S2"); + checkArraySingle(ImgOut1, DFT_exp_imag2, 8, "DFT_RtoC_Imag_S2"); + + //Scenario 3 + vDSP_DFT_Setup zrop_Setup_New = vDSP_DFT_zrop_CreateSetup(zrop_Setup, 8, vDSP_DFT_FORWARD); + ASSERT_TRUE_MSG(zrop_Setup != nullptr, "FAILED: vDSP_DFT_zrop_CreateSetup failed!\n"); + + float RealIn5[4] = {1, 3, 5, 7}; + float RealIn6[4] = {2, 4, 6, 8}; + + vDSP_DFT_Execute(zrop_Setup_New, RealIn5, RealIn6, RealOut1, ImgOut1); + + float DFT_exp_real3[] = {72.000000, -8.000000, -8.000000, -8.000000, 0.000000, 0.000000, 0.000000, 0.000000}; + float DFT_exp_imag3[] = {-8.000000, 19.313709, 8.000000, 3.313708, 0.000000, 0.000000, 0.000000, 0.000000}; + + checkArraySingle(RealOut1, DFT_exp_real3, 8, "DFT_RtoC_Real_S3"); + checkArraySingle(ImgOut1, DFT_exp_imag3, 8, "DFT_RtoC_Imag_S3"); + + vDSP_DFT_DestroySetup(zrop_Setup); +} + +//Test for validating the single-precision complex-to-real IDFT for a vector +TEST(Accelerate, vDSP_IDFT_ComplexToReal_Float) { + vDSP_DFT_Setup zrop_Setup_Inverse = vDSP_DFT_zrop_CreateSetup(NULL, 8, vDSP_DFT_INVERSE); + ASSERT_TRUE_MSG(zrop_Setup_Inverse != nullptr, "FAILED: vDSP_DFT_zrop_CreateSetup failed!\n"); + + //Scenario 1 + float RealIn1 [] = {45, -20.606602, -10, 0.606602, 55, 0.606602, -10, -20.606602}; + float ImgIn1 [] = {0, 9.292893, -27, -10.707107, 0, 10.707107, 27, -9.292893}; + + float RealOut1 [4] = {0}; + float RealOut2 [4] = {0}; + + vDSP_DFT_Execute(zrop_Setup_Inverse, RealIn1, ImgIn1, RealOut1, RealOut2); + + float DFT_exp_real1[] = {-14.999998, 25, 65, 105}; + float DFT_exp_real2[] = {71, 23, 127, -41}; + + checkArraySingle(RealOut1, DFT_exp_real1, 4, "IDFT_CtoR_Real1_S1"); + checkArraySingle(RealOut2, DFT_exp_real2, 4, "IDFT_CtoR_Real2_S1"); + + //Scenario 2 + float RealIn2 [] = {36, -4, -4, -4, -4, -4, -4, -4}; + float ImgIn2 [] = {0, 9.66, 4, 1.66, 0, -1.66, -4, -9.66}; + + vDSP_DFT_Execute(zrop_Setup_Inverse, RealIn2, ImgIn2, RealOut1, RealOut2); + + float DFT_exp_real3[] = {12, 28, 44, 60}; + float DFT_exp_real4[] = {11.991104, 27.991104, 44.008896, 60.008896}; + + checkArraySingle(RealOut1, DFT_exp_real3, 4, "IDFT_CtoR_Real1_S2"); + checkArraySingle(RealOut2, DFT_exp_real4, 4, "IDFT_CtoR_Real2_S2"); + + //Scenario 3 + float RealIn3 [] = {60, -2, -2, -2, -40, -2, -2, -2}; + float ImgIn3 [] = {0, 16.142136, 10, 12.142136, 0, -12.142136, -10, -16.142136}; + + vDSP_DFT_Execute(zrop_Setup_Inverse, RealIn3, ImgIn3, RealOut1, RealOut2); + + float DFT_exp_real5[] = {48, 56, 64, 72}; + float DFT_exp_real6[] = {0, 40, 80, 120}; + + checkArraySingle(RealOut1, DFT_exp_real5, 4, "IDFT_CtoR_Real1_S3"); + checkArraySingle(RealOut2, DFT_exp_real6, 4, "IDFT_CtoR_Real2_S3"); + + vDSP_DFT_DestroySetup(zrop_Setup_Inverse); +} + +//Test for validating the single-precision complex DFT for a vector +TEST(Accelerate, vDSP_DFT_ComplexToComplex_Float) { + vDSP_DFT_Setup zop_Setup = vDSP_DFT_zop_CreateSetup(NULL, 8, vDSP_DFT_FORWARD); + ASSERT_TRUE_MSG(zop_Setup != nullptr, "FAILED: vDSP_DFT_zop_CreateSetup failed!\n"); + + float RealIn1 [8] = {1, 3, 5, 7, 9, 11, 13, 15}; + float ImgIn1 [8] = {2, 4, 6, 8, 10, 12, 14, 16}; + float RealOut1 [8] = {0}; + float ImgOut1[8] = {0}; + + vDSP_DFT_Execute(zop_Setup, RealIn1, ImgIn1, RealOut1, ImgOut1); + + float DFT_exp_real[] = {64.000000, -27.313709, -16.000000, -11.313708, -8.000000, -4.686292, 0.000000, 11.313708}; + float DFT_exp_imag[] = {72.000000, 11.313708, 0.000000, -4.686292, -8.000000, -11.313708, -16.000000, -27.313709}; + + checkArraySingle(RealOut1, DFT_exp_real, 8, "DFT_CtoC_Real_S1"); + checkArraySingle(ImgOut1, DFT_exp_imag, 8, "DFT_CtoC_Imag_S1"); + + vDSP_DFT_DestroySetup(zop_Setup); +} + +//Test for validating the single-precision complex IDFT for a vector +TEST(Accelerate, vDSP_IDFT_ComplexToComplex_Float) { + vDSP_DFT_Setup zop_Setup_Inverse = vDSP_DFT_zop_CreateSetup(NULL, 8, vDSP_DFT_INVERSE); + ASSERT_TRUE_MSG(zop_Setup_Inverse != nullptr, "FAILED: vDSP_DFT_zop_CreateSetup failed!\n"); + + float RealIn1 [8] = {1, 3, 5, 7, 9, 11, 13, 15}; + float ImgIn1 [8] = {2, 4, 6, 8, 10, 12, 14, 16}; + float RealOut1 [8] = {0}; + float ImgOut1[8] = {0}; + + vDSP_DFT_Execute(zop_Setup_Inverse, RealIn1, ImgIn1, RealOut1, ImgOut1); + + float DFT_exp_real[] = {64.000000, 11.313708, 0.000000, -4.686292, -8.000000, -11.313708, -16.000000, -27.313709}; + float DFT_exp_imag[] = {72.000000, -27.313709, -16.000000, -11.313708, -8.000000, -4.686292, 0.000000, 11.313708}; + + checkArraySingle(RealOut1, DFT_exp_real, 8, "IDFT_CtoC_Real_S1"); + checkArraySingle(ImgOut1, DFT_exp_imag, 8, "IDFT_CtoC_Imag_S1"); + + vDSP_DFT_DestroySetup(zop_Setup_Inverse); +} + +//Test for validating the double-precision real-to-complex DFT for a vector +TEST(Accelerate, vDSP_DFT_RealToComplex_Double) { + vDSP_DFT_SetupD zrop_Setup = vDSP_DFT_zrop_CreateSetupD(NULL, 8, vDSP_DFT_FORWARD); + ASSERT_TRUE_MSG(zrop_Setup != nullptr, "FAILED: vDSP_DFT_zrop_CreateSetupD failed!\n"); + + double RealIn1 [4] = {1, 3, 5, 7}; + double RealIn2 [4] = {2, 4, 6, 8}; + + double RealOut1 [8] = {0}; + double ImgOut1[8] = {0}; + + vDSP_DFT_ExecuteD(zrop_Setup, RealIn1, RealIn2, RealOut1, ImgOut1); + + double DFT_exp_real[] = {72.000000, -8.000000, -8.000000, -8.000000, 0.000000, 0.000000, 0.000000, 0.000000}; + double DFT_exp_imag[] = {-8.000000, 19.313708, 8.000000, 3.313708, 0.000000, 0.000000, 0.000000, 0.000000}; + + checkArrayDouble(RealOut1, DFT_exp_real, 8, "DFT_RtoC_Real_S1"); + checkArrayDouble(ImgOut1, DFT_exp_imag, 8, "DFT_RtoC_Imag_S1"); + + vDSP_DFT_DestroySetupD(zrop_Setup); +} + +//Test for validating the double-precision complex-to-real IDFT for a vector +TEST(Accelerate, vDSP_IDFT_ComplexToReal_Double) { + vDSP_DFT_SetupD zrop_Setup_Inverse = vDSP_DFT_zrop_CreateSetupD(NULL, 8, vDSP_DFT_INVERSE); + ASSERT_TRUE_MSG(zrop_Setup_Inverse != nullptr, "FAILED: vDSP_DFT_zrop_CreateSetupD failed!\n"); + + double RealIn1 [8] = {36, -4, -4, -4, -4, -4, -4, -4}; + double ImgIn1 [8] = {0, 9.66, 4, 1.66, 0, -1.66, -4, -9.66}; + + double RealOut1 [4] = {0}; + double RealOut2 [4] = {0}; + + vDSP_DFT_ExecuteD(zrop_Setup_Inverse, RealIn1, ImgIn1, RealOut1, RealOut2); + + double DFT_exp_real1[] = {12, 28, 44, 60}; + double DFT_exp_real2[] = {11.991102, 27.991102, 44.008898, 60.008898}; + + checkArrayDouble(RealOut1, DFT_exp_real1, 4, "IDFT_CtoR_Real_S1"); + checkArrayDouble(RealOut2, DFT_exp_real2, 4, "IDFT_CtoR_Real_S1"); + + vDSP_DFT_DestroySetupD(zrop_Setup_Inverse); +} + +//Test for validating the double-precision complex DFT for a vector +TEST(Accelerate, vDSP_DFT_ComplexToComplex_Double) { + vDSP_DFT_SetupD zop_Setup = vDSP_DFT_zop_CreateSetupD(NULL, 8, vDSP_DFT_FORWARD); + ASSERT_TRUE_MSG(zop_Setup != nullptr, "FAILED: vDSP_DFT_zop_CreateSetupD failed!\n"); + + double RealIn1 [8] = {1, 3, 5, 7, 9, 11, 13, 15}; + double ImgIn1 [8] = {2, 4, 6, 8, 10, 12, 14, 16}; + double RealOut1 [8] = {0}; + double ImgOut1[8] = {0}; + + vDSP_DFT_ExecuteD(zop_Setup, RealIn1, ImgIn1, RealOut1, ImgOut1); + + double DFT_exp_real[] = {64.000000, -27.313708, -16.000000, -11.313708, -8.000000, -4.686292, 0.000000, 11.313708}; + double DFT_exp_imag[] = {72.000000, 11.313708, 0.000000, -4.686292, -8.000000, -11.313708, -16.000000, -27.313708}; + + checkArrayDouble(RealOut1, DFT_exp_real, 8, "DFT_CtoC_Real_S1"); + checkArrayDouble(ImgOut1, DFT_exp_imag, 8, "DFT_CtoC_Imag_S1"); + + vDSP_DFT_DestroySetupD(zop_Setup); +} + +//Test for validating the double-precision complex IDFT for a vector +TEST(Accelerate, vDSP_IDFT_ComplexToComplexDoubleCase1) { + vDSP_DFT_SetupD zop_Setup_Inverse = vDSP_DFT_zop_CreateSetupD(NULL, 8, vDSP_DFT_INVERSE); + ASSERT_TRUE_MSG(zop_Setup_Inverse != nullptr, "FAILED: vDSP_DFT_zop_CreateSetupD failed!\n"); + + double RealIn1 [8] = {1, 3, 5, 7, 9, 11, 13, 15}; + double ImgIn1 [8] = {2, 4, 6, 8, 10, 12, 14, 16}; + double RealOut1 [8] = {0}; + double ImgOut1[8] = {0}; + + vDSP_DFT_ExecuteD(zop_Setup_Inverse, RealIn1, ImgIn1, RealOut1, ImgOut1); + + double DFT_exp_real[] = {64.000000, 11.313708, 0.000000, -4.686292, -8.000000, -11.313708, -16.000000, -27.313708}; + double DFT_exp_imag[] = {72.000000, -27.313709, -16.000000, -11.313708, -8.000000, -4.686292, 0.000000, 11.313708}; + + checkArrayDouble(RealOut1, DFT_exp_real, 8, "IDFT_CtoC_Real_S1"); + checkArrayDouble(ImgOut1, DFT_exp_imag, 8, "IDFT_CtoC_Imag_S1"); + + vDSP_DFT_DestroySetupD(zop_Setup_Inverse); +} + +//Test for validating the DFT length requirements +TEST(Accelerate, vDSP_DFT_LengthCheck) { + vDSP_DFT_Setup zop_Setup1 = vDSP_DFT_zop_CreateSetup(NULL, 16, vDSP_DFT_FORWARD); + ASSERT_TRUE_MSG(zop_Setup1 != nullptr, "FAILED: vDSP_DFT_zop_CreateSetup failed!\n"); + vDSP_DFT_DestroySetup(zop_Setup1); + + vDSP_DFT_Setup zop_Setup2 = vDSP_DFT_zop_CreateSetup(NULL, 40, vDSP_DFT_FORWARD); + ASSERT_TRUE_MSG(zop_Setup2 != nullptr, "FAILED: vDSP_DFT_zop_CreateSetup failed!\n"); + vDSP_DFT_DestroySetup(zop_Setup2); + + vDSP_DFT_Setup zop_Setup3 = vDSP_DFT_zop_CreateSetup(NULL, 42, vDSP_DFT_FORWARD); + ASSERT_TRUE_MSG(zop_Setup3 == nullptr, "FAILED: vDSP_DFT_zop_CreateSetup failed!\n"); + vDSP_DFT_DestroySetup(zop_Setup3); + + vDSP_DFT_Setup zrop_Setup_Inverse1 = vDSP_DFT_zrop_CreateSetup(NULL, 80, vDSP_DFT_INVERSE); + ASSERT_TRUE_MSG(zrop_Setup_Inverse1 != nullptr, "FAILED: vDSP_DFT_zrop_CreateSetup failed!\n"); + vDSP_DFT_DestroySetup(zrop_Setup_Inverse1); + + vDSP_DFT_Setup zrop_Setup_Inverse2 = vDSP_DFT_zrop_CreateSetup(NULL, 40, vDSP_DFT_INVERSE); + ASSERT_TRUE_MSG(zrop_Setup_Inverse2 == nullptr, "FAILED: vDSP_DFT_zrop_CreateSetup failed!\n"); + vDSP_DFT_DestroySetup(zrop_Setup_Inverse2); +} diff --git a/tests/unittests/Accelerate/vImageTest.mm b/tests/unittests/Accelerate/vImageTest.mm new file mode 100644 index 0000000000..b468099d77 --- /dev/null +++ b/tests/unittests/Accelerate/vImageTest.mm @@ -0,0 +1,411 @@ +//****************************************************************************** +// +// Copyright (c) 2016, Intel Corporation +// Copyright (c) 2015 Microsoft Corporation. All rights reserved. +// +// This code is licensed under the MIT License (MIT). +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +// +//****************************************************************************** + +#include "gtest-api.h" +#import +#import + +vImage_Buffer src, dest; +vImage_Error Error; +Pixel_8888 background = {10, 20, 30, 40}; +uint8_t output[10][10][4]; +uint8_t input[10][10][4] = { + { {232, 19, 158, 38} , {175, 197, 114, 68} , {188, 109, 120, 80} , {102, 47, 102, 143} , {142, 79, 160, 52} , + {3, 124, 114, 32} , {70, 18, 189, 123} , {116, 190, 247, 56} , {17, 157, 230, 3} , {139, 79, 204, 66} }, + { {22, 167, 208, 141} , {155, 125, 158, 16} , {54, 157, 56, 53} , {118, 49, 163, 35} , {84, 116, 30, 193} , + {22, 211, 24, 89} , {251, 223, 42, 123} , {228, 43, 13, 211} , {160, 178, 15, 154} , {233, 126, 200, 14} }, + { {30, 19, 234, 106} , {32, 185, 15, 104} , {6, 228, 183, 173} , {125, 202, 177, 131} , {16, 162, 158, 159} , + {216, 57, 71, 143} , {122, 143, 112, 87} , {189, 144, 239, 236} , {95, 180, 30, 98} , {232, 214, 53, 197} }, + { {135, 82, 39, 148} , {205, 228, 83, 235} , {181, 162, 217, 40} , {97, 52, 67, 171} , {90, 217, 201, 56} , + {80, 186, 53, 12} , {76, 140, 215, 199} , {170, 121, 47, 13} , {0, 39, 144, 8} , {4, 80, 190, 216} }, + { {123, 146, 8, 155} , {183, 109, 225, 194} , {46, 19, 206, 189} , {163, 213, 34, 70} , {185, 39, 238, 87} , + {40, 232, 122, 39} , {47, 60, 46, 190} , {208, 250, 209, 173} , {145, 180, 180, 44} , {67, 206, 69, 192} }, + { {219, 115, 68, 101} , {87, 180, 76, 218} , {74, 187, 198, 37} , {140, 95, 122, 36} , {213, 172, 196, 195} , + {10, 203, 125, 126} , {72, 4, 64, 186} , {51, 121, 202, 80} , {29, 79, 245, 189} , {142, 75, 238, 239} }, + { {230, 205, 0, 231} , {63, 217, 101, 208} , {204, 96, 39, 128} , {123, 227, 126, 39} , {63, 206, 216, 199} , + {29, 190, 44, 165} , {79, 13, 19, 85} , {222, 165, 237, 0} , {185, 41, 44, 87} , {3, 84, 65, 15} }, + { {241, 167, 79, 177} , {239, 251, 223, 225} , {83, 209, 249, 214} , {228, 253, 167, 162} , {188, 197, 165, 141} , + {248, 19, 25, 206} , {75, 24, 140, 90} , {226, 173, 195, 138} , {227, 71, 248, 126} , {77, 196, 38, 144} }, + { {219, 12, 68, 56} , {220, 157, 193, 212} , {66, 158, 114, 63} , {132, 139, 48, 90} , {169, 245, 250, 162} , + {65, 70, 120, 156} , {112, 38, 180, 241} , {190, 117, 158, 74} , {158, 125, 174, 208} , {177, 30, 159, 130} }, + { {128, 72, 127, 148} , {214, 177, 72, 74} , {75, 93, 108, 33} , {138, 250, 173, 49} , {96, 170, 14, 237} , + {228, 28, 102, 130} , {30, 111, 160, 103} , {215, 250, 183, 203} , {203, 146, 10, 94} , {155, 184, 212, 184} } + }; + +static void vImageInit(void) { + src.data = input; + src.height = 10; + src.width = 10; + src.rowBytes = src.width*4; + + dest.data = output; + dest.width = 10; + dest.height = 10; + dest.rowBytes = dest.width*4; +} + +TEST(Accelerate, BoxConvolve) { + vImageInit(); + + Error = vImageBoxConvolve_ARGB8888(&src, &dest, NULL, 0, 0, 5, 5, NULL, kvImageCopyInPlace); + uint8_t kvICiP_Expected [10][10][4] = { + { {232, 19, 158, 38} , {175, 197, 114, 68} , {188, 109, 120, 80} , {102, 47, 102, 143} , {142, 79, 160, 52} , + {3, 124, 114, 32} , {70, 18, 189, 123} , {116, 190, 247, 56} , {17, 157, 230, 3} , {139, 79, 204, 66} }, + { {22, 167, 208, 141} , {155, 125, 158, 16} , {54, 157, 56, 53} , {118, 49, 163, 35} , {84, 116, 30, 193} , + {22, 211, 24, 89} , {251, 223, 42, 123} , {228, 43, 13, 211} , {160, 178, 15, 154} , {233, 126, 200, 14} }, + { {30, 19, 234, 106} , {32, 185, 15, 104} , {116, 125, 134, 113} , {108, 140, 124, 103} , {101, 130, 124, 107} , + {118, 133, 123, 113} , {111, 140, 125, 103} , {117, 143, 122, 109} , {95, 180, 30, 98} , {232, 214, 53, 197} }, + { {135, 82, 39, 148} , {205, 228, 83, 235} , {111, 137, 134, 122} , {105, 151, 128, 112} , {101, 141, 125, 113} , + {121, 138, 119, 122} , {112, 140, 121, 124} , {116, 140, 118, 130} , {0, 39, 144, 8} , {4, 80, 190, 216} }, + { {123, 146, 8, 155} , {183, 109, 225, 194} , {121, 151, 129, 136} , {107, 163, 132, 126} , {100, 140, 130, 118} , + {113, 145, 134, 115} , {105, 134, 138, 114} , {101, 128, 123, 121} , {145, 180, 180, 44} , {67, 206, 69, 192} }, + { {219, 115, 68, 101} , {87, 180, 76, 218} , {152, 162, 134, 146} , {130, 166, 141, 136} , {113, 137, 132, 122} , + {125, 143, 131, 114} , {118, 126, 145, 113} , {100, 118, 128, 118} , {29, 79, 245, 189} , {142, 75, 238, 239} }, + { {230, 205, 0, 231} , {63, 217, 101, 208} , {156, 161, 136, 144} , {130, 163, 145, 142} , {114, 132, 130, 132} , + {131, 139, 138, 125} , {129, 121, 154, 135} , {115, 111, 134, 133} , {185, 41, 44, 87} , {3, 84, 65, 15} }, + { {241, 167, 79, 177} , {239, 251, 223, 225} , {154, 170, 128, 137} , {136, 168, 131, 140} , {118, 136, 127, 131} , + {134, 139, 137, 132} , {135, 119, 141, 145} , {128, 102, 135, 136} , {227, 71, 248, 126} , {77, 196, 38, 144} }, + { {219, 12, 68, 56} , {220, 157, 193, 212} , {66, 158, 114, 63} , {132, 139, 48, 90} , {169, 245, 250, 162} , + {65, 70, 120, 156} , {112, 38, 180, 241} , {190, 117, 158, 74} , {158, 125, 174, 208} , {177, 30, 159, 130} }, + { {128, 72, 127, 148} , {214, 177, 72, 74} , {75, 93, 108, 33} , {138, 250, 173, 49} , {96, 170, 14, 237} , + {228, 28, 102, 130} , {30, 111, 160, 103} , {215, 250, 183, 203} , {203, 146, 10, 94} , {155, 184, 212, 184} } + }; + + uint8_t* res = reinterpret_cast(dest.data); + for(int i = 0; i<10; ++i) { + for(int j = 0; j<10; ++j) { + for(int k = 0; k<4; ++k) { + ASSERT_NEAR_MSG(kvICiP_Expected[i][j][k], res[i*40 + j*4 + k], 2, + "Flag :kvImageCopyInPlace\t Source and Destination of same size\0"); + } + } + } + + + Error = vImageBoxConvolve_ARGB8888(&src, &dest, NULL, 0, 0, 5, 5, NULL, kvImageEdgeExtend); + uint8_t kvIEE_Expected [10][10][4] ={ + { {143, 94, 154, 75} , {135, 100, 144, 84} , {126, 111, 134, 90} , {106, 126, 115, 89} , {101, 107, 123, 99} , + {107, 109, 139, 105} , {97, 126, 142, 92} , {111, 129, 150, 88} , {137, 126, 167, 91} , {149, 133, 173, 84} }, + { {132, 105, 143, 93} , {128, 108, 135, 99} , {121, 122, 132, 101} , {108, 138, 115, 94} , {102, 122, 126, 101} , + {110, 119, 129, 107} , {100, 132, 131, 93} , {111, 129, 137, 94} , {128, 124, 156, 104} , {134, 125, 160, 101} }, + { {114, 113, 133, 117} , {117, 118, 129, 115} , {116, 125, 134, 113} , {108, 140, 124, 103} , {101, 130, 124, 107} , + {118, 133, 123, 113} , {111, 140, 125, 103} , {117, 143, 122, 109} , {130, 139, 136, 124} , {134, 144, 140, 122} }, + { {104, 127, 124, 128} , {109, 130, 124, 120} , {111, 137, 134, 122} , {105, 151, 128, 112} , {101, 141, 125, 113} , + {121, 138, 119, 122} , {112, 140, 121, 124} , {116, 140, 118, 130} , {128, 132, 132, 148} , {132, 138, 143, 151} }, + { {132, 132, 96, 150} , {128, 141, 103, 138} , {121, 151, 129, 136} , {107, 163, 132, 126} , {100, 140, 130, 118} , + {113, 145, 134, 115} , {105, 134, 138, 114} , {101, 128, 123, 121} , {103, 120, 131, 136} , {106, 132, 137, 140} }, + { {168, 152, 88, 165} , {160, 157, 101, 152} , {152, 162, 134, 146} , {130, 166, 141, 136} , {113, 137, 132, 122} , + {125, 143, 131, 114} , {118, 126, 145, 113} , {100, 118, 128, 118} , {96, 111, 137, 129} , {94, 127, 142, 131} }, + { {174, 141, 92, 154} , {165, 152, 103, 141} , {156, 161, 136, 144} , {130, 163, 145, 142} , {114, 132, 130, 132} , + {131, 139, 138, 125} , {129, 121, 154, 135} , {115, 111, 134, 133} , {118, 106, 139, 134} , {122, 124, 144, 131} }, + { {177, 138, 96, 142} , {166, 153, 108, 129} , {154, 170, 128, 137} , {136, 168, 131, 140} , {118, 136, 127, 131} , + {134, 139, 137, 132} , {135, 119, 141, 145} , {128, 102, 135, 136} , {127, 105, 147, 133} , {135, 120, 153, 133} }, + { {172, 128, 99, 142} , {164, 152, 111, 127} , {151, 171, 121, 136} , {145, 163, 121, 137} , {120, 136, 121, 130} , + {143, 148, 134, 136} , {151, 124, 126, 144} , {149, 112, 127, 132} , {140, 125, 139, 127} , {150, 141, 140, 128} }, + { {160, 111, 116, 123} , {157, 141, 124, 112} , {150, 163, 122, 125} , {156, 154, 118, 128} , {123, 132, 125, 127} , + {150, 148, 134, 145} , {159, 128, 122, 154} , {162, 121, 138, 146} , {151, 145, 153, 149} , {168, 160, 154, 157} } + }; + + res = reinterpret_cast(dest.data); + for(int i = 0; i<10; ++i) { + for(int j = 0; j<10; ++j) { + for(int k = 0; k<4; ++k) { + ASSERT_NEAR_MSG(kvIEE_Expected[i][j][k], res[i*40 + j*4 + k], 2, + "Flag :kvImageEdgeExtend\t Source and Destination of same size\0"); + } + } + } + + + Error = vImageBoxConvolve_ARGB8888(&src, &dest, NULL, 0, 0, 5, 5, NULL, kvImageTruncateKernel); + uint8_t kvITC_Expected [10][10][4] = { + { {99, 134, 138, 87} , {103, 125, 141, 91} , {99, 124, 136, 99} , {96, 137, 110, 98} , {101, 128, 113, 108} , + {120, 121, 123, 121} , {115, 135, 112, 117} , {140, 139, 119, 109} , {154, 141, 131, 114} , {157, 146, 137, 115} }, + { {118, 140, 132, 100} , {116, 127, 131, 105} , {109, 130, 132, 107} , {105, 145, 113, 99} , {102, 134, 123, 105} , + {116, 126, 121, 113} , {107, 136, 117, 102} , {121, 133, 122, 104} , {131, 130, 136, 113} , {132, 129, 134, 106} }, + { {118, 130, 135, 116} , {119, 126, 128, 115} , {116, 125, 134, 113} , {108, 140, 124, 103} , {101, 130, 124, 107} , + {118, 133, 123, 113} , {111, 140, 125, 103} , {117, 143, 122, 109} , {128, 139, 134, 120} , {134, 146, 138, 112} }, + { {103, 141, 132, 127} , {110, 136, 127, 118} , {111, 137, 134, 122} , {105, 151, 128, 112} , {101, 141, 125, 113} , + {121, 138, 119, 122} , {112, 140, 121, 124} , {116, 140, 118, 130} , {126, 130, 128, 142} , {130, 136, 138, 138} }, + { {121, 145, 113, 151} , {123, 148, 111, 136} , {121, 151, 129, 136} , {107, 163, 132, 126} , {100, 140, 130, 118} , + {113, 145, 134, 115} , {105, 134, 138, 114} , {101, 128, 123, 121} , {107, 117, 132, 127} , {116, 132, 146, 119} }, + { {154, 158, 121, 167} , {153, 161, 116, 149} , {152, 162, 134, 146} , {130, 166, 141, 136} , {113, 137, 132, 122} , + {125, 143, 131, 114} , {118, 126, 145, 113} , {100, 118, 128, 118} , {105, 106, 142, 121} , {117, 125, 157, 111} }, + { {153, 149, 123, 161} , {154, 158, 117, 140} , {156, 161, 136, 144} , {130, 163, 145, 142} , {114, 132, 130, 132} , + {131, 139, 138, 125} , {129, 121, 154, 135} , {115, 111, 134, 133} , {125, 103, 146, 132} , {140, 128, 164, 123} }, + { {157, 153, 114, 142} , {156, 163, 118, 125} , {154, 170, 128, 137} , {136, 168, 131, 140} , {118, 136, 127, 131} , + {134, 139, 137, 132} , {135, 119, 141, 145} , {128, 102, 135, 136} , {131, 102, 149, 131} , {151, 124, 161, 127} }, + { {165, 151, 114, 147} , {163, 168, 118, 132} , {156, 175, 127, 142} , {144, 168, 127, 145} , {122, 137, 123, 135} , + {143, 144, 136, 134} , {150, 120, 134, 142} , {145, 104, 126, 129} , {146, 111, 139, 120} , {170, 132, 144, 117} }, + { {165, 144, 137, 134} , {165, 162, 135, 125} , {162, 170, 137, 136} , {159, 161, 135, 144} , {129, 134, 134, 138} , + {156, 139, 139, 145} , {162, 119, 142, 154} , {159, 105, 140, 148} , {154, 122, 155, 145} , {181, 144, 153, 145} } + }; + + res = reinterpret_cast(dest.data); + for(int i = 0; i<10; ++i) { + for(int j = 0; j<10; ++j) { + for(int k = 0; k<4; ++k) { + ASSERT_NEAR_MSG(kvITC_Expected[i][j][k], res[i*40 + j*4 + k], 2, + "Flag :kvImageTruncateKernel\t Source and Destination of same size\0"); + } + } + } + + + Error = vImageBoxConvolve_ARGB8888(&src, &dest, NULL, 0, 0, 5, 5, background, kvImageBackgroundColorFill); + uint8_t kvICBCF_Expected [10][10][4] = { + { {42, 61, 69, 57} , {55, 71, 83, 64} , {63, 82, 93, 76} , {62, 90, 78, 75} , {65, 85, 80, 81} , + {76, 80, 86, 89} , {73, 89, 79, 86} , {88, 91, 83, 81} , {79, 78, 79, 76} , {63, 65, 68, 67} }, + { {62, 78, 79, 69} , {78, 88, 95, 82} , {90, 108, 112, 94} , {86, 120, 97, 87} , {84, 111, 104, 92} , + {95, 105, 103, 99} , {88, 113, 99, 90} , {99, 110, 103, 91} , {88, 90, 98, 87} , {69, 72, 80, 72} }, + { {75, 86, 93, 86} , {97, 105, 109, 100} , {116, 125, 134, 113} , {108, 140, 124, 103} , {101, 130, 124, 107} , + {118, 133, 123, 113} , {111, 140, 125, 103} , {117, 143, 122, 109} , {105, 115, 113, 104} , {84, 95, 95, 83} }, + { {66, 92, 91, 92} , {90, 113, 107, 102} , {111, 137, 134, 122} , {105, 151, 128, 112} , {101, 141, 125, 113} , + {121, 138, 119, 122} , {112, 140, 121, 124} , {116, 140, 118, 130} , {103, 108, 108, 122} , {82, 89, 95, 99} }, + { {77, 95, 80, 107} , {101, 123, 95, 117} , {121, 151, 129, 136} , {107, 163, 132, 126} , {100, 140, 130, 118} , + {113, 145, 134, 115} , {105, 134, 138, 114} , {101, 128, 123, 121} , {88, 98, 112, 109} , {74, 87, 100, 87} }, + { {97, 103, 84, 116} , {125, 133, 99, 127} , {152, 162, 134, 146} , {130, 166, 141, 136} , {113, 137, 132, 122} , + {125, 143, 131, 114} , {118, 126, 145, 113} , {100, 118, 128, 118} , {86, 89, 119, 105} , {74, 83, 106, 83} }, + { {96, 97, 86, 112} , {125, 130, 100, 120} , {156, 161, 136, 144} , {130, 163, 145, 142} , {114, 132, 130, 132} , + {131, 139, 138, 125} , {129, 121, 154, 135} , {115, 111, 134, 133} , {102, 86, 122, 113} , {88, 85, 110, 90} }, + { {98, 100, 81, 101} , {127, 134, 100, 108} , {154, 170, 128, 137} , {136, 168, 131, 140} , {118, 136, 127, 131} , + {134, 139, 137, 132} , {135, 119, 141, 145} , {128, 102, 135, 136} , {107, 86, 125, 113} , {94, 82, 108, 92} }, + { {84, 83, 71, 92} , {108, 115, 86, 99} , {127, 144, 107, 122} , {117, 138, 108, 124} , {99, 113, 104, 116} , + {116, 119, 115, 115} , {122, 100, 113, 122} , {118, 87, 107, 111} , {97, 78, 100, 91} , {87, 74, 85, 77} }, + { {66, 65, 69, 74} , {85, 88, 80, 81} , {101, 110, 94, 98} , {100, 105, 93, 102} , {81, 88, 93, 99} , + {98, 91, 95, 103} , {101, 79, 97, 108} , {99, 71, 96, 105} , {79, 69, 90, 90} , {72, 64, 74, 78} } + }; + + res = reinterpret_cast(dest.data); + for(int i = 0; i<10; ++i) { + for(int j = 0; j<10; ++j) { + for(int k = 0; k<4; ++k) { + ASSERT_NEAR_MSG(kvICBCF_Expected[i][j][k], res[i*40 + j*4 + k], 2, + "Flag :kvImageBackgroundColorFill\t Source and Destination of same size\0"); + } + } + } + + + dest.width = 6; + dest.height = 6; + dest.rowBytes = dest.width*4; + + Error = vImageBoxConvolve_ARGB8888(&src, &dest, NULL, 2, 2, 5, 5, NULL, kvImageCopyInPlace); + uint8_t Copy[6][6][4] = { + { {116, 125, 134, 113} , {108, 140, 124, 103} , {101, 130, 124, 107} , {118, 133, 123, 113} , {111, 140, 125, 103} , + {117, 143, 122, 109} }, + { {111, 137, 134, 122} , {105, 151, 128, 112} , {101, 141, 125, 113} , {121, 138, 119, 122} , {112, 140, 121, 124} , + {116, 140, 118, 130} }, + { {121, 151, 129, 136} , {107, 163, 132, 126} , {100, 140, 130, 118} , {113, 145, 134, 115} , {105, 134, 138, 114} , + {101, 128, 123, 121} }, + { {152, 162, 134, 146} , {130, 166, 141, 136} , {113, 137, 132, 122} , {125, 143, 131, 114} , {118, 126, 145, 113} , + {100, 118, 128, 118} }, + { {156, 161, 136, 144} , {130, 163, 145, 142} , {114, 132, 130, 132} , {131, 139, 138, 125} , {129, 121, 154, 135} , + {115, 111, 134, 133} }, + { {154, 170, 128, 137} , {136, 168, 131, 140} , {118, 136, 127, 131} , {134, 139, 137, 132} , {135, 119, 141, 145} , + {128, 102, 135, 136} } + }; + + res = reinterpret_cast(dest.data); + for(int i = 0; i<6; ++i) { + for(int j = 0; j<6; ++j) { + for(int k = 0; k<4; ++k) { + ASSERT_NEAR_MSG(Copy[i][j][k], res[i*24 + j*4 + k], 2, "Flag :kvImageCopyInPlace\t FULL KERNEL\0"); + } + } + } + + + Error = vImageBoxConvolve_ARGB8888(&src, &dest, NULL, 2, 2, 5, 5, NULL, kvImageEdgeExtend); + uint8_t EE[6][6][4] = { + { {116, 125, 134, 113} , {108, 140, 124, 103} , {101, 130, 124, 107} , {118, 133, 123, 113} , {111, 140, 125, 103} , + {117, 143, 122, 109} }, + { {111, 137, 134, 122} , {105, 151, 128, 112} , {101, 141, 125, 113} , {121, 138, 119, 122} , {112, 140, 121, 124} , + {116, 140, 118, 130} }, + { {121, 151, 129, 136} , {107, 163, 132, 126} , {100, 140, 130, 118} , {113, 145, 134, 115} , {105, 134, 138, 114} , + {101, 128, 123, 121} }, + { {152, 162, 134, 146} , {130, 166, 141, 136} , {113, 137, 132, 122} , {125, 143, 131, 114} , {118, 126, 145, 113} , + {100, 118, 128, 118} }, + { {156, 161, 136, 144} , {130, 163, 145, 142} , {114, 132, 130, 132} , {131, 139, 138, 125} , {129, 121, 154, 135} , + {115, 111, 134, 133} }, + { {154, 170, 128, 137} , {136, 168, 131, 140} , {118, 136, 127, 131} , {134, 139, 137, 132} , {135, 119, 141, 145} , + {128, 102, 135, 136} } + }; + + res = reinterpret_cast(dest.data); + for(int i = 0; i<6; ++i) { + for(int j = 0; j<6; ++j) { + for(int k = 0; k<4; ++k) { + ASSERT_NEAR_MSG(EE[i][j][k], res[i*24 + j*4 + k], 2, "Flag :kvImageEdgeExtend\t FULL KERNEL\0"); + } + } + } + + + Error = vImageBoxConvolve_ARGB8888(&src, &dest, NULL, 2, 2, 5, 5, NULL, kvImageTruncateKernel); + uint8_t TK[6][6][4] = { + { {116, 125, 134, 113} , {108, 140, 124, 103} , {101, 130, 124, 107} , {118, 133, 123, 113} , {111, 140, 125, 103} , + {117, 143, 122, 109} }, + { {111, 137, 134, 122} , {105, 151, 128, 112} , {101, 141, 125, 113} , {121, 138, 119, 122} , {112, 140, 121, 124} , + {116, 140, 118, 130} }, + { {121, 151, 129, 136} , {107, 163, 132, 126} , {100, 140, 130, 118} , {113, 145, 134, 115} , {105, 134, 138, 114} , + {101, 128, 123, 121} }, + { {152, 162, 134, 146} , {130, 166, 141, 136} , {113, 137, 132, 122} , {125, 143, 131, 114} , {118, 126, 145, 113} , + {100, 118, 128, 118} }, + { {156, 161, 136, 144} , {130, 163, 145, 142} , {114, 132, 130, 132} , {131, 139, 138, 125} , {129, 121, 154, 135} , + {115, 111, 134, 133} }, + { {154, 170, 128, 137} , {136, 168, 131, 140} , {118, 136, 127, 131} , {134, 139, 137, 132} , {135, 119, 141, 145} , + {128, 102, 135, 136} } + }; + + res = reinterpret_cast(dest.data); + for(int i = 0; i<6; ++i) { + for(int j = 0; j<6; ++j) { + for(int k = 0; k<4; ++k) { + ASSERT_NEAR_MSG(TK[i][j][k], res[i*24 + j*4 + k], 2, "Flag :kvImageTruncateKernel\t FULL KERNEL\0"); + } + } + } + + + Error = vImageBoxConvolve_ARGB8888(&src, &dest, NULL, 2, 2, 5, 5, background, kvImageBackgroundColorFill); + uint8_t BCF[6][6][4] = { + { {116, 125, 134, 113} , {108, 140, 124, 103} , {101, 130, 124, 107} , {118, 133, 123, 113} , {111, 140, 125, 103} , + {117, 143, 122, 109} }, + { {111, 137, 134, 122} , {105, 151, 128, 112} , {101, 141, 125, 113} , {121, 138, 119, 122} , {112, 140, 121, 124} , + {116, 140, 118, 130} }, + { {121, 151, 129, 136} , {107, 163, 132, 126} , {100, 140, 130, 118} , {113, 145, 134, 115} , {105, 134, 138, 114} , + {101, 128, 123, 121} }, + { {152, 162, 134, 146} , {130, 166, 141, 136} , {113, 137, 132, 122} , {125, 143, 131, 114} , {118, 126, 145, 113} , + {100, 118, 128, 118} }, + { {156, 161, 136, 144} , {130, 163, 145, 142} , {114, 132, 130, 132} , {131, 139, 138, 125} , {129, 121, 154, 135} , + {115, 111, 134, 133} }, + { {154, 170, 128, 137} , {136, 168, 131, 140} , {118, 136, 127, 131} , {134, 139, 137, 132} , {135, 119, 141, 145} , + {128, 102, 135, 136} } + }; + + res = reinterpret_cast(dest.data); + for(int i = 0; i<6; ++i) { + for(int j = 0; j<6; ++j) { + for(int k = 0; k<4; ++k) { + ASSERT_NEAR_MSG(BCF[i][j][k], res[i*24 + j*4 + k], 2, "Flag :kvImageBackgroundColorFill\t FULL KERNEL\0"); + } + } + } + +} + +TEST(Accelerate, MatrixMultiply) { + vImageInit(); + + int16_t A[] = { 149, 124, 116, 114, + 174, 190, 18, 191, + 80, 128, 65, 44, + 3, 70, 168, 188 }; + + double meandivisor = 400; + + Error = vImageMatrixMultiply_ARGB8888(&src, &dest, A, meandivisor, NULL, NULL, 0); + + uint8_t matMultExpected [10][10][4] = { + { {127, 138, 110, 110}, {174, 196, 107, 188}, {142, 162, 113, 156}, {80, 112, 108, 130}, {120, 142, 93, 120}, + {78, 102, 38, 88}, {73, 112, 103, 107}, {176, 215, 106, 177}, {121, 154, 51, 107}, {127, 157, 105, 131} }, + { {123, 177, 107, 175}, {144, 161, 83, 129}, {100, 119, 54, 121}, {98, 118, 78, 91}, {89, 125, 116, 173}, + {105, 130, 57, 151}, {200, 219, 141, 240}, {108, 132, 159, 186}, {141, 166, 122, 205}, {182, 199, 112, 155} }, + { {67, 112, 92, 93}, {96, 121, 64, 148}, {139, 199, 114, 212}, {171, 214, 129, 213}, {109, 160, 104, 174}, + {121, 142, 137, 164}, {131, 157, 97, 156}, {183, 245, 199, 255}, {120, 142, 82, 162}, {192, 225, 168, 255} }, + { {95, 119, 111, 151}, {194, 240, 182, 255}, {182, 210, 112, 172}, {73, 106, 113, 140}, {169, 205, 92, 178}, + {121, 132, 45, 123}, {134, 194, 147, 206}, {125, 127, 68, 118}, {46, 66, 29, 38}, {76, 138, 126, 162} }, + { {112, 137, 109, 179}, {162, 214, 176, 220}, {68, 122, 127, 134}, {161, 175, 92, 185}, {134, 167, 131, 138}, + {141, 168, 58, 154}, {54, 91, 104, 136}, {229, 255, 178, 255}, {169, 196, 98, 168}, {130, 174, 121, 215} }, + { {146, 162, 122, 172}, {128, 175, 137, 222}, {149, 182, 78, 150}, {118, 134, 80, 116}, {195, 245, 183, 255}, + {118, 162, 85, 173}, {43, 77, 110, 117}, {113, 152, 87, 132}, {96, 158, 131, 162}, {135, 198, 184, 215} }, + { {177, 209, 173, 255}, {140, 191, 132, 230}, {127, 144, 124, 168}, {170, 193, 83, 176}, {158, 221, 146, 234}, + {103, 142, 93, 181}, {40, 52, 62, 71}, {202, 223, 110, 168}, {96, 106, 99, 118}, {51, 64, 22, 55} }, + { {180, 210, 165, 240}, {245, 255, 211, 255}, {173, 242, 164, 251}, {230, 255, 173, 255}, {190, 229, 149, 232}, + {107, 130, 163, 179}, {67, 95, 83, 91}, {199, 239, 163, 233}, {166, 206, 162, 185}, {123, 154, 98, 187} }, + { {101, 105, 99, 102}, {190, 242, 191, 255}, {117, 143, 71, 136}, {120, 138, 90, 152}, {221, 255, 169, 255}, + {80, 119, 107, 138}, {96, 153, 165, 183}, {154, 178, 117, 162}, {150, 200, 167, 222}, {112, 143, 133, 143} }, + { {106, 140, 123, 154}, {172, 186, 113, 188}, {90, 108, 57, 93}, {195, 225, 100, 201}, {114, 156, 137, 221}, + {118, 139, 139, 151}, {92, 131, 83, 128}, {227, 255, 189, 255}, {142, 152, 107, 173}, {182, 235, 165, 242} } + }; + + uint8_t* res = reinterpret_cast(dest.data); + for(int i = 0; i<10; ++i) { + for(int j = 0; j<10; ++j) { + for(int k = 0; k<4; ++k) { + ASSERT_NEAR_MSG(matMultExpected[i][j][k], res[i*40 + j*4 + k], 2, "vImageMatrixMultiply\0"); + } + } + } + + // Checking for cut off at 255 + + int16_t B[] = { 192, 152, 16, 22, + 95, 97, 149, 70, + 186, 162, 21, 69, + 58, 77, 187, 119 }; + + Error = vImageMatrixMultiply_ARGB8888(&src, &dest, B, meandivisor/2, NULL, NULL, 0); + + uint8_t matMultExpected2 [10][10][4] = { + { {255, 255, 85, 109}, {255, 255, 236, 168}, {255, 255, 184, 148}, {255, 238, 188, 148}, {255, 255, 136, 129}, + {177, 167, 135, 102}, {255, 255, 154, 152}, {255, 255, 229, 198}, {255, 255, 145, 138}, {255, 255, 153, 153} }, + { {255, 255, 255, 217}, {255, 255, 137, 125}, {194, 183, 177, 112}, {255, 255, 96, 107}, {220, 219, 255, 175}, + {169, 173, 245, 138}, {255, 255, 255, 193}, {255, 255, 249, 170}, {255, 255, 255, 177}, {255, 255, 147, 147} }, + { {255, 255, 140, 154}, {163, 166, 239, 135}, {255, 255, 255, 247}, {255, 255, 255, 223}, {255, 255, 255, 208}, + {255, 255, 201, 153}, {255, 255, 209, 154}, {255, 255, 255, 255}, {233, 222, 236, 142}, {255, 255, 255, 236} }, + { {248, 231, 214, 145}, {255, 255, 255, 255}, {255, 255, 195, 175}, {230, 219, 213, 154}, {255, 255, 242, 189}, + {218, 199, 162, 99}, {255, 255, 255, 250}, {255, 231, 121, 85}, {155, 139, 52, 68}, {255, 255, 255, 223} }, + { {240, 230, 255, 160}, {255, 255, 255, 251}, {255, 255, 216, 195}, {255, 255, 241, 146}, {255, 255, 150, 168}, + {255, 255, 225, 151}, {171, 175, 231, 155}, {255, 255, 255, 255}, {255, 255, 206, 167}, {255, 255, 255, 218} }, + { {255, 255, 205, 148}, {255, 255, 255, 229}, {255, 255, 201, 164}, {255, 255, 128, 112}, {255, 255, 255, 255}, + {255, 255, 255, 190}, {184, 180, 189, 142}, {255, 255, 190, 165}, {255, 255, 255, 228}, {255, 255, 255, 255} }, + { {255, 255, 255, 234}, {255, 255, 255, 241}, {255, 255, 212, 146}, {255, 255, 229, 160}, {255, 255, 255, 255}, + {207, 213, 255, 183}, {124, 114, 97, 70}, {255, 255, 166, 164}, {255, 230, 131, 102}, {108, 101, 84, 61} }, + { {255, 255, 255, 218}, {255, 255, 255, 255}, {255, 255, 255, 255}, {255, 255, 255, 255}, {255, 255, 255, 230}, + {255, 255, 229, 165}, {240, 217, 123, 118}, {255, 255, 255, 235}, {255, 255, 215, 210}, {244, 240, 255, 176} }, + { {255, 249, 86, 85}, {255, 255, 255, 255}, {255, 243, 194, 139}, {255, 241, 203, 133}, {255, 255, 255, 255}, + {252, 241, 216, 166}, {255, 255, 255, 231}, {255, 255, 188, 160}, {255, 255, 255, 245}, {255, 255, 175, 162} }, + { {255, 255, 216, 171}, {255, 255, 226, 154}, {226, 202, 117, 98}, {255, 255, 255, 192}, {255, 255, 255, 216}, + {255, 255, 171, 147}, {255, 246, 198, 159}, {255, 255, 255, 255}, {255, 255, 214, 133}, {255, 255, 255, 255} } + }; + + res = reinterpret_cast(dest.data); + for(int i = 0; i<10; ++i) { + for(int j = 0; j<10; ++j) { + for(int k = 0; k<4; ++k) { + ASSERT_NEAR_MSG(matMultExpected2[i][j][k], res[i*40 + j*4 + k], 2, "vImageMatrixMultiply : 255 Cut-Off test\0"); + } + } + } + + + // Checking for cut off at 0 + + Error = vImageMatrixMultiply_ARGB8888(&src, &dest, B, -1 * meandivisor, NULL, NULL, 0); + + res = reinterpret_cast(dest.data); + for(int i = 0; i<10; ++i) { + for(int j = 0; j<10; ++j) { + for(int k = 0; k<4; ++k) { + ASSERT_NEAR_MSG(0, res[i*40 + j*4 + k], 2, "vImageMatrixMultiply : 255 Cut-Off test\0"); + } + } + } +} \ No newline at end of file