mirror of
				https://github.com/NVIDIA/cuda-samples.git
				synced 2025-10-31 19:47:48 +08:00 
			
		
		
		
	
		
			
				
	
	
		
			456 lines
		
	
	
		
			14 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			456 lines
		
	
	
		
			14 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
| /* Copyright (c) 2022, NVIDIA CORPORATION. All rights reserved.
 | |
|  *
 | |
|  * Redistribution and use in source and binary forms, with or without
 | |
|  * modification, are permitted provided that the following conditions
 | |
|  * are met:
 | |
|  *  * Redistributions of source code must retain the above copyright
 | |
|  *    notice, this list of conditions and the following disclaimer.
 | |
|  *  * Redistributions in binary form must reproduce the above copyright
 | |
|  *    notice, this list of conditions and the following disclaimer in the
 | |
|  *    documentation and/or other materials provided with the distribution.
 | |
|  *  * Neither the name of NVIDIA CORPORATION nor the names of its
 | |
|  *    contributors may be used to endorse or promote products derived
 | |
|  *    from this software without specific prior written permission.
 | |
|  *
 | |
|  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY
 | |
|  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 | |
|  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 | |
|  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR
 | |
|  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 | |
|  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 | |
|  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
 | |
|  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
 | |
|  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 | |
|  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 | |
|  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 | |
|  */
 | |
| 
 | |
| /**
 | |
| **************************************************************************
 | |
| * \file BmpUtil.cpp
 | |
| * \brief Contains basic image operations implementation.
 | |
| *
 | |
| * This file contains implementation of basic bitmap loading, saving,
 | |
| * conversions to different representations and memory management routines.
 | |
| */
 | |
| 
 | |
| #include "Common.h"
 | |
| #include "BmpUtil.h"
 | |
| 
 | |
| #if defined(WIN32) || defined(_WIN32) || defined(WIN64) || defined(_WIN64)
 | |
| #pragma warning(disable : 4996)  // disable deprecated warning
 | |
| #endif
 | |
| 
 | |
| /**
 | |
| **************************************************************************
 | |
| *  The routine clamps the input value to integer byte range [0, 255]
 | |
| *
 | |
| * \param x          [IN] - Input value
 | |
| *
 | |
| * \return Pointer to the created plane
 | |
| */
 | |
| int clamp_0_255(int x) { return (x < 0) ? 0 : ((x > 255) ? 255 : x); }
 | |
| 
 | |
| /**
 | |
| **************************************************************************
 | |
| *  Float round to nearest value
 | |
| *
 | |
| * \param num            [IN] - Float value to round
 | |
| *
 | |
| * \return The closest to the input float integer value
 | |
| */
 | |
| float round_f(float num) {
 | |
|   float NumAbs = fabs(num);
 | |
|   int NumAbsI = (int)(NumAbs + 0.5f);
 | |
|   float sign = num > 0 ? 1.0f : -1.0f;
 | |
|   return sign * NumAbsI;
 | |
| }
 | |
| 
 | |
| /**
 | |
| **************************************************************************
 | |
| *  Memory allocator, returns aligned format frame with 8bpp pixels.
 | |
| *
 | |
| * \param width          [IN] - Width of image buffer to be allocated
 | |
| * \param height         [IN] - Height of image buffer to be allocated
 | |
| * \param pStepBytes     [OUT] - Step between two sequential rows
 | |
| *
 | |
| * \return Pointer to the created plane
 | |
| */
 | |
| byte *MallocPlaneByte(int width, int height, int *pStepBytes) {
 | |
|   byte *ptr;
 | |
|   *pStepBytes = ((int)ceil(width / 16.0f)) * 16;
 | |
|   //#ifdef __ALLOW_ALIGNED_MEMORY_MANAGEMENT
 | |
|   //  ptr = (byte *)_aligned_malloc(*pStepBytes * height, 16);
 | |
|   //#else
 | |
|   ptr = (byte *)malloc(*pStepBytes * height);
 | |
|   //#endif
 | |
|   return ptr;
 | |
| }
 | |
| 
 | |
| /**
 | |
| **************************************************************************
 | |
| *  Memory allocator, returns aligned format frame with 16bpp float pixels.
 | |
| *
 | |
| * \param width          [IN] - Width of image buffer to be allocated
 | |
| * \param height         [IN] - Height of image buffer to be allocated
 | |
| * \param pStepBytes     [OUT] - Step between two sequential rows
 | |
| *
 | |
| * \return Pointer to the created plane
 | |
| */
 | |
| short *MallocPlaneShort(int width, int height, int *pStepBytes) {
 | |
|   short *ptr;
 | |
|   *pStepBytes = ((int)ceil((width * sizeof(short)) / 16.0f)) * 16;
 | |
|   //#ifdef __ALLOW_ALIGNED_MEMORY_MANAGEMENT
 | |
|   //  ptr = (float *)_aligned_malloc(*pStepBytes * height, 16);
 | |
|   //#else
 | |
|   ptr = (short *)malloc(*pStepBytes * height);
 | |
|   //#endif
 | |
|   *pStepBytes = *pStepBytes / sizeof(short);
 | |
|   return ptr;
 | |
| }
 | |
| 
 | |
| /**
 | |
| **************************************************************************
 | |
| *  Memory allocator, returns aligned format frame with 32bpp float pixels.
 | |
| *
 | |
| * \param width          [IN] - Width of image buffer to be allocated
 | |
| * \param height         [IN] - Height of image buffer to be allocated
 | |
| * \param pStepBytes     [OUT] - Step between two sequential rows
 | |
| *
 | |
| * \return Pointer to the created plane
 | |
| */
 | |
| float *MallocPlaneFloat(int width, int height, int *pStepBytes) {
 | |
|   float *ptr;
 | |
|   *pStepBytes = ((int)ceil((width * sizeof(float)) / 16.0f)) * 16;
 | |
|   //#ifdef __ALLOW_ALIGNED_MEMORY_MANAGEMENT
 | |
|   //  ptr = (float *)_aligned_malloc(*pStepBytes * height, 16);
 | |
|   //#else
 | |
|   ptr = (float *)malloc(*pStepBytes * height);
 | |
|   //#endif
 | |
|   *pStepBytes = *pStepBytes / sizeof(float);
 | |
|   return ptr;
 | |
| }
 | |
| 
 | |
| /**
 | |
| **************************************************************************
 | |
| *  Copies byte plane to float plane
 | |
| *
 | |
| * \param ImgSrc             [IN] - Source byte plane
 | |
| * \param StrideB            [IN] - Source plane stride
 | |
| * \param ImgDst             [OUT] - Destination float plane
 | |
| * \param StrideF            [IN] - Destination plane stride
 | |
| * \param Size               [IN] - Size of area to copy
 | |
| *
 | |
| * \return None
 | |
| */
 | |
| void CopyByte2Float(byte *ImgSrc, int StrideB, float *ImgDst, int StrideF,
 | |
|                     ROI Size) {
 | |
|   for (int i = 0; i < Size.height; i++) {
 | |
|     for (int j = 0; j < Size.width; j++) {
 | |
|       ImgDst[i * StrideF + j] = (float)ImgSrc[i * StrideB + j];
 | |
|     }
 | |
|   }
 | |
| }
 | |
| 
 | |
| /**
 | |
| **************************************************************************
 | |
| *  Copies float plane to byte plane (with clamp)
 | |
| *
 | |
| * \param ImgSrc             [IN] - Source float plane
 | |
| * \param StrideF            [IN] - Source plane stride
 | |
| * \param ImgDst             [OUT] - Destination byte plane
 | |
| * \param StrideB            [IN] - Destination plane stride
 | |
| * \param Size               [IN] - Size of area to copy
 | |
| *
 | |
| * \return None
 | |
| */
 | |
| void CopyFloat2Byte(float *ImgSrc, int StrideF, byte *ImgDst, int StrideB,
 | |
|                     ROI Size) {
 | |
|   for (int i = 0; i < Size.height; i++) {
 | |
|     for (int j = 0; j < Size.width; j++) {
 | |
|       ImgDst[i * StrideB + j] =
 | |
|           (byte)clamp_0_255((int)(round_f(ImgSrc[i * StrideF + j])));
 | |
|     }
 | |
|   }
 | |
| }
 | |
| 
 | |
| /**
 | |
| **************************************************************************
 | |
| *  Memory deallocator, deletes aligned format frame.
 | |
| *
 | |
| * \param ptr            [IN] - Pointer to the plane
 | |
| *
 | |
| * \return None
 | |
| */
 | |
| void FreePlane(void *ptr) {
 | |
|   //#ifdef __ALLOW_ALIGNED_MEMORY_MANAGEMENT
 | |
|   //  if (ptr)
 | |
|   //  {
 | |
|   //      _aligned_free(ptr);
 | |
|   //  }
 | |
|   //#else
 | |
|   if (ptr) {
 | |
|     free(ptr);
 | |
|   }
 | |
| 
 | |
|   //#endif
 | |
| }
 | |
| 
 | |
| /**
 | |
| **************************************************************************
 | |
| *  Performs addition of given value to each pixel in the plane
 | |
| *
 | |
| * \param Value              [IN] - Value to add
 | |
| * \param ImgSrcDst          [IN/OUT] - Source float plane
 | |
| * \param StrideF            [IN] - Source plane stride
 | |
| * \param Size               [IN] - Size of area to copy
 | |
| *
 | |
| * \return None
 | |
| */
 | |
| void AddFloatPlane(float Value, float *ImgSrcDst, int StrideF, ROI Size) {
 | |
|   for (int i = 0; i < Size.height; i++) {
 | |
|     for (int j = 0; j < Size.width; j++) {
 | |
|       ImgSrcDst[i * StrideF + j] += Value;
 | |
|     }
 | |
|   }
 | |
| }
 | |
| 
 | |
| /**
 | |
| **************************************************************************
 | |
| *  Performs multiplication of given value with each pixel in the plane
 | |
| *
 | |
| * \param Value              [IN] - Value for multiplication
 | |
| * \param ImgSrcDst          [IN/OUT] - Source float plane
 | |
| * \param StrideF            [IN] - Source plane stride
 | |
| * \param Size               [IN] - Size of area to copy
 | |
| *
 | |
| * \return None
 | |
| */
 | |
| void MulFloatPlane(float Value, float *ImgSrcDst, int StrideF, ROI Size) {
 | |
|   for (int i = 0; i < Size.height; i++) {
 | |
|     for (int j = 0; j < Size.width; j++) {
 | |
|       ImgSrcDst[i * StrideF + j] *= Value;
 | |
|     }
 | |
|   }
 | |
| }
 | |
| 
 | |
| /**
 | |
| **************************************************************************
 | |
| *  This function performs acquisition of image dimensions
 | |
| *
 | |
| * \param FileName       [IN] - Image name to load
 | |
| * \param Width          [OUT] - Image width from file header
 | |
| * \param Height         [OUT] - Image height from file header
 | |
| *
 | |
| * \return Status code
 | |
| */
 | |
| int PreLoadBmp(char *FileName, int *Width, int *Height) {
 | |
|   BMPFileHeader FileHeader;
 | |
|   BMPInfoHeader InfoHeader;
 | |
|   FILE *fh;
 | |
| 
 | |
|   if (!(fh = fopen(FileName, "rb"))) {
 | |
|     return 1;  // invalid filename
 | |
|   }
 | |
| 
 | |
|   fread(&FileHeader, sizeof(BMPFileHeader), 1, fh);
 | |
| 
 | |
|   if (FileHeader._bm_signature != 0x4D42) {
 | |
|     return 2;  // invalid file format
 | |
|   }
 | |
| 
 | |
|   fread(&InfoHeader, sizeof(BMPInfoHeader), 1, fh);
 | |
| 
 | |
|   if (InfoHeader._bm_color_depth != 24) {
 | |
|     return 3;  // invalid color depth
 | |
|   }
 | |
| 
 | |
|   if (InfoHeader._bm_compressed) {
 | |
|     return 4;  // invalid compression property
 | |
|   }
 | |
| 
 | |
|   *Width = InfoHeader._bm_image_width;
 | |
|   *Height = InfoHeader._bm_image_height;
 | |
| 
 | |
|   fclose(fh);
 | |
|   return 0;
 | |
| }
 | |
| 
 | |
| /**
 | |
| **************************************************************************
 | |
| *  This function performs loading of bitmap luma
 | |
| *
 | |
| * \param FileName       [IN] - Image name to load
 | |
| * \param Stride         [IN] - Image stride
 | |
| * \param ImSize         [IN] - Image size
 | |
| * \param Img            [OUT] - Prepared buffer
 | |
| *
 | |
| * \return None
 | |
| */
 | |
| void LoadBmpAsGray(char *FileName, int Stride, ROI ImSize, byte *Img) {
 | |
|   BMPFileHeader FileHeader;
 | |
|   BMPInfoHeader InfoHeader;
 | |
|   FILE *fh;
 | |
|   fh = fopen(FileName, "rb");
 | |
| 
 | |
|   fread(&FileHeader, sizeof(BMPFileHeader), 1, fh);
 | |
|   fread(&InfoHeader, sizeof(BMPInfoHeader), 1, fh);
 | |
| 
 | |
|   for (int i = ImSize.height - 1; i >= 0; i--) {
 | |
|     for (int j = 0; j < ImSize.width; j++) {
 | |
|       int r = 0, g = 0, b = 0;
 | |
|       fread(&b, 1, 1, fh);
 | |
|       fread(&g, 1, 1, fh);
 | |
|       fread(&r, 1, 1, fh);
 | |
|       int val = (313524 * r + 615514 * g + 119537 * b + 524288) >> 20;
 | |
|       Img[i * Stride + j] = (byte)clamp_0_255(val);
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   fclose(fh);
 | |
|   return;
 | |
| }
 | |
| 
 | |
| /**
 | |
| **************************************************************************
 | |
| *  This function performs dumping of bitmap luma on HDD
 | |
| *
 | |
| * \param FileName       [OUT] - Image name to dump to
 | |
| * \param Img            [IN] - Image luma to dump
 | |
| * \param Stride         [IN] - Image stride
 | |
| * \param ImSize         [IN] - Image size
 | |
| *
 | |
| * \return None
 | |
| */
 | |
| void DumpBmpAsGray(char *FileName, byte *Img, int Stride, ROI ImSize) {
 | |
|   FILE *fp = NULL;
 | |
|   fp = fopen(FileName, "wb");
 | |
| 
 | |
|   if (fp == NULL) {
 | |
|     return;
 | |
|   }
 | |
| 
 | |
|   BMPFileHeader FileHeader;
 | |
|   BMPInfoHeader InfoHeader;
 | |
| 
 | |
|   // init headers
 | |
|   FileHeader._bm_signature = 0x4D42;
 | |
|   FileHeader._bm_file_size = 54 + 3 * ImSize.width * ImSize.height;
 | |
|   FileHeader._bm_reserved = 0;
 | |
|   FileHeader._bm_bitmap_data = 0x36;
 | |
|   InfoHeader._bm_bitmap_size = 0;
 | |
|   InfoHeader._bm_color_depth = 24;
 | |
|   InfoHeader._bm_compressed = 0;
 | |
|   InfoHeader._bm_hor_resolution = 0;
 | |
|   InfoHeader._bm_image_height = ImSize.height;
 | |
|   InfoHeader._bm_image_width = ImSize.width;
 | |
|   InfoHeader._bm_info_header_size = 40;
 | |
|   InfoHeader._bm_num_colors_used = 0;
 | |
|   InfoHeader._bm_num_important_colors = 0;
 | |
|   InfoHeader._bm_num_of_planes = 1;
 | |
|   InfoHeader._bm_ver_resolution = 0;
 | |
| 
 | |
|   fwrite(&FileHeader, sizeof(BMPFileHeader), 1, fp);
 | |
|   fwrite(&InfoHeader, sizeof(BMPInfoHeader), 1, fp);
 | |
| 
 | |
|   for (int i = ImSize.height - 1; i >= 0; i--) {
 | |
|     for (int j = 0; j < ImSize.width; j++) {
 | |
|       fwrite(&(Img[i * Stride + j]), 1, 1, fp);
 | |
|       fwrite(&(Img[i * Stride + j]), 1, 1, fp);
 | |
|       fwrite(&(Img[i * Stride + j]), 1, 1, fp);
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   fclose(fp);
 | |
| }
 | |
| 
 | |
| /**
 | |
| **************************************************************************
 | |
| *  This function performs dumping of 8x8 block from float plane
 | |
| *
 | |
| * \param PlaneF         [IN] - Image plane
 | |
| * \param StrideF        [IN] - Image stride
 | |
| * \param Fname          [OUT] - File name to dump to
 | |
| *
 | |
| * \return None
 | |
| */
 | |
| void DumpBlockF(float *PlaneF, int StrideF, char *Fname) {
 | |
|   FILE *fp = fopen(Fname, "wb");
 | |
| 
 | |
|   for (int i = 0; i < 8; i++) {
 | |
|     for (int j = 0; j < 8; j++) {
 | |
|       fprintf(fp, "%.*f  ", 14, PlaneF[i * StrideF + j]);
 | |
|     }
 | |
| 
 | |
|     fprintf(fp, "\n");
 | |
|   }
 | |
| 
 | |
|   fclose(fp);
 | |
| }
 | |
| 
 | |
| /**
 | |
| **************************************************************************
 | |
| *  This function performs dumping of 8x8 block from byte plane
 | |
| *
 | |
| * \param Plane          [IN] - Image plane
 | |
| * \param Stride         [IN] - Image stride
 | |
| * \param Fname          [OUT] - File name to dump to
 | |
| *
 | |
| * \return None
 | |
| */
 | |
| void DumpBlock(byte *Plane, int Stride, char *Fname) {
 | |
|   FILE *fp = fopen(Fname, "wb");
 | |
| 
 | |
|   for (int i = 0; i < 8; i++) {
 | |
|     for (int j = 0; j < 8; j++) {
 | |
|       fprintf(fp, "%.3d  ", Plane[i * Stride + j]);
 | |
|     }
 | |
| 
 | |
|     fprintf(fp, "\n");
 | |
|   }
 | |
| 
 | |
|   fclose(fp);
 | |
| }
 | |
| 
 | |
| /**
 | |
| **************************************************************************
 | |
| *  This function performs evaluation of Mean Square Error between two images
 | |
| *
 | |
| * \param Img1           [IN] - Image 1
 | |
| * \param Img2           [IN] - Image 2
 | |
| * \param Stride         [IN] - Image stride
 | |
| * \param Size           [IN] - Image size
 | |
| *
 | |
| * \return Mean Square Error between images
 | |
| */
 | |
| float CalculateMSE(byte *Img1, byte *Img2, int Stride, ROI Size) {
 | |
|   uint32 Acc = 0;
 | |
| 
 | |
|   for (int i = 0; i < Size.height; i++) {
 | |
|     for (int j = 0; j < Size.width; j++) {
 | |
|       int TmpDiff = Img1[i * Stride + j] - Img2[i * Stride + j];
 | |
|       TmpDiff *= TmpDiff;
 | |
|       Acc += TmpDiff;
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   return ((float)Acc) / (Size.height * Size.width);
 | |
| }
 | |
| 
 | |
| /**
 | |
| **************************************************************************
 | |
| *  This function performs evaluation of Peak Signal to Noise Ratio between
 | |
| *  two images
 | |
| *
 | |
| * \param Img1           [IN] - Image 1
 | |
| * \param Img2           [IN] - Image 2
 | |
| * \param Stride         [IN] - Image stride
 | |
| * \param Size           [IN] - Image size
 | |
| *
 | |
| * \return Peak Signal to Noise Ratio between images
 | |
| */
 | |
| float CalculatePSNR(byte *Img1, byte *Img2, int Stride, ROI Size) {
 | |
|   float MSE = CalculateMSE(Img1, Img2, Stride, Size);
 | |
|   return 10 * log10(255 * 255 / MSE);
 | |
| }
 |