mirror of
https://github.com/NVIDIA/cuda-samples.git
synced 2026-10-26 06:38:16 +08:00
Apply consistent code formatting across the repo. Add clang-format and pre-commit hooks.
This commit is contained in:
@@ -29,100 +29,107 @@
|
||||
#include <stdlib.h>
|
||||
|
||||
#if defined(WIN32) || defined(_WIN32) || defined(WIN64) || defined(_WIN64)
|
||||
#pragma warning(disable : 4996) // disable deprecated warning
|
||||
#pragma warning(disable : 4996) // disable deprecated warning
|
||||
#endif
|
||||
|
||||
#pragma pack(1)
|
||||
|
||||
typedef struct {
|
||||
short type;
|
||||
int size;
|
||||
short reserved1;
|
||||
short reserved2;
|
||||
int offset;
|
||||
typedef struct
|
||||
{
|
||||
short type;
|
||||
int size;
|
||||
short reserved1;
|
||||
short reserved2;
|
||||
int offset;
|
||||
} BMPHeader;
|
||||
|
||||
typedef struct {
|
||||
int size;
|
||||
int width;
|
||||
int height;
|
||||
short planes;
|
||||
short bitsPerPixel;
|
||||
unsigned compression;
|
||||
unsigned imageSize;
|
||||
int xPelsPerMeter;
|
||||
int yPelsPerMeter;
|
||||
int clrUsed;
|
||||
int clrImportant;
|
||||
typedef struct
|
||||
{
|
||||
int size;
|
||||
int width;
|
||||
int height;
|
||||
short planes;
|
||||
short bitsPerPixel;
|
||||
unsigned compression;
|
||||
unsigned imageSize;
|
||||
int xPelsPerMeter;
|
||||
int yPelsPerMeter;
|
||||
int clrUsed;
|
||||
int clrImportant;
|
||||
} BMPInfoHeader;
|
||||
|
||||
// Isolated definition
|
||||
typedef struct { unsigned char x, y, z, w; } uchar4;
|
||||
typedef struct
|
||||
{
|
||||
unsigned char x, y, z, w;
|
||||
} uchar4;
|
||||
|
||||
extern "C" void LoadBMPFile(uchar4 **dst, int *width, int *height,
|
||||
const char *name) {
|
||||
BMPHeader hdr;
|
||||
BMPInfoHeader infoHdr;
|
||||
int x, y;
|
||||
extern "C" void LoadBMPFile(uchar4 **dst, int *width, int *height, const char *name)
|
||||
{
|
||||
BMPHeader hdr;
|
||||
BMPInfoHeader infoHdr;
|
||||
int x, y;
|
||||
|
||||
FILE *fd;
|
||||
FILE *fd;
|
||||
|
||||
printf("Loading %s...\n", name);
|
||||
printf("Loading %s...\n", name);
|
||||
|
||||
if (sizeof(uchar4) != 4) {
|
||||
printf("***Bad uchar4 size***\n");
|
||||
exit(EXIT_SUCCESS);
|
||||
}
|
||||
|
||||
if (!(fd = fopen(name, "rb"))) {
|
||||
printf("***BMP load error: file access denied***\n");
|
||||
exit(EXIT_SUCCESS);
|
||||
}
|
||||
|
||||
fread(&hdr, sizeof(hdr), 1, fd);
|
||||
|
||||
if (hdr.type != 0x4D42) {
|
||||
printf("***BMP load error: bad file format***\n");
|
||||
exit(EXIT_SUCCESS);
|
||||
}
|
||||
|
||||
fread(&infoHdr, sizeof(infoHdr), 1, fd);
|
||||
|
||||
if (infoHdr.bitsPerPixel != 24) {
|
||||
printf("***BMP load error: invalid color depth***\n");
|
||||
exit(EXIT_SUCCESS);
|
||||
}
|
||||
|
||||
if (infoHdr.compression) {
|
||||
printf("***BMP load error: compressed image***\n");
|
||||
exit(EXIT_SUCCESS);
|
||||
}
|
||||
|
||||
*width = infoHdr.width;
|
||||
*height = infoHdr.height;
|
||||
*dst = (uchar4 *)malloc(*width * *height * 4);
|
||||
|
||||
printf("BMP width: %u\n", infoHdr.width);
|
||||
printf("BMP height: %u\n", infoHdr.height);
|
||||
|
||||
fseek(fd, hdr.offset - sizeof(hdr) - sizeof(infoHdr), SEEK_CUR);
|
||||
|
||||
for (y = 0; y < infoHdr.height; y++) {
|
||||
for (x = 0; x < infoHdr.width; x++) {
|
||||
(*dst)[(y * infoHdr.width + x)].z = fgetc(fd);
|
||||
(*dst)[(y * infoHdr.width + x)].y = fgetc(fd);
|
||||
(*dst)[(y * infoHdr.width + x)].x = fgetc(fd);
|
||||
if (sizeof(uchar4) != 4) {
|
||||
printf("***Bad uchar4 size***\n");
|
||||
exit(EXIT_SUCCESS);
|
||||
}
|
||||
|
||||
for (x = 0; x < (4 - (3 * infoHdr.width) % 4) % 4; x++) fgetc(fd);
|
||||
}
|
||||
if (!(fd = fopen(name, "rb"))) {
|
||||
printf("***BMP load error: file access denied***\n");
|
||||
exit(EXIT_SUCCESS);
|
||||
}
|
||||
|
||||
if (ferror(fd)) {
|
||||
printf("***Unknown BMP load error.***\n");
|
||||
free(*dst);
|
||||
exit(EXIT_SUCCESS);
|
||||
} else
|
||||
printf("BMP file loaded successfully!\n");
|
||||
fread(&hdr, sizeof(hdr), 1, fd);
|
||||
|
||||
fclose(fd);
|
||||
if (hdr.type != 0x4D42) {
|
||||
printf("***BMP load error: bad file format***\n");
|
||||
exit(EXIT_SUCCESS);
|
||||
}
|
||||
|
||||
fread(&infoHdr, sizeof(infoHdr), 1, fd);
|
||||
|
||||
if (infoHdr.bitsPerPixel != 24) {
|
||||
printf("***BMP load error: invalid color depth***\n");
|
||||
exit(EXIT_SUCCESS);
|
||||
}
|
||||
|
||||
if (infoHdr.compression) {
|
||||
printf("***BMP load error: compressed image***\n");
|
||||
exit(EXIT_SUCCESS);
|
||||
}
|
||||
|
||||
*width = infoHdr.width;
|
||||
*height = infoHdr.height;
|
||||
*dst = (uchar4 *)malloc(*width * *height * 4);
|
||||
|
||||
printf("BMP width: %u\n", infoHdr.width);
|
||||
printf("BMP height: %u\n", infoHdr.height);
|
||||
|
||||
fseek(fd, hdr.offset - sizeof(hdr) - sizeof(infoHdr), SEEK_CUR);
|
||||
|
||||
for (y = 0; y < infoHdr.height; y++) {
|
||||
for (x = 0; x < infoHdr.width; x++) {
|
||||
(*dst)[(y * infoHdr.width + x)].z = fgetc(fd);
|
||||
(*dst)[(y * infoHdr.width + x)].y = fgetc(fd);
|
||||
(*dst)[(y * infoHdr.width + x)].x = fgetc(fd);
|
||||
}
|
||||
|
||||
for (x = 0; x < (4 - (3 * infoHdr.width) % 4) % 4; x++)
|
||||
fgetc(fd);
|
||||
}
|
||||
|
||||
if (ferror(fd)) {
|
||||
printf("***Unknown BMP load error.***\n");
|
||||
free(*dst);
|
||||
exit(EXIT_SUCCESS);
|
||||
}
|
||||
else
|
||||
printf("BMP file loaded successfully!\n");
|
||||
|
||||
fclose(fd);
|
||||
}
|
||||
|
||||
@@ -35,10 +35,11 @@
|
||||
* See supplied whitepaper for more explanations.
|
||||
*/
|
||||
|
||||
#include <helper_cuda.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <helper_cuda.h>
|
||||
|
||||
#include "imageDenoising.h"
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
@@ -52,21 +53,21 @@ int iDivUp(int a, int b) { return ((a % b) != 0) ? (a / b + 1) : (a / b); }
|
||||
|
||||
__device__ float lerpf(float a, float b, float c) { return a + (b - a) * c; }
|
||||
|
||||
__device__ float vecLen(float4 a, float4 b) {
|
||||
return ((b.x - a.x) * (b.x - a.x) + (b.y - a.y) * (b.y - a.y) +
|
||||
(b.z - a.z) * (b.z - a.z));
|
||||
__device__ float vecLen(float4 a, float4 b)
|
||||
{
|
||||
return ((b.x - a.x) * (b.x - a.x) + (b.y - a.y) * (b.y - a.y) + (b.z - a.z) * (b.z - a.z));
|
||||
}
|
||||
|
||||
__device__ TColor make_color(float r, float g, float b, float a) {
|
||||
return ((int)(a * 255.0f) << 24) | ((int)(b * 255.0f) << 16) |
|
||||
((int)(g * 255.0f) << 8) | ((int)(r * 255.0f) << 0);
|
||||
__device__ TColor make_color(float r, float g, float b, float a)
|
||||
{
|
||||
return ((int)(a * 255.0f) << 24) | ((int)(b * 255.0f) << 16) | ((int)(g * 255.0f) << 8) | ((int)(r * 255.0f) << 0);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Global data handlers and parameters
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Texture object and channel descriptor for image texture
|
||||
cudaTextureObject_t texImage;
|
||||
cudaTextureObject_t texImage;
|
||||
cudaChannelFormatDesc uchar4tex = cudaCreateChannelDesc<uchar4>();
|
||||
|
||||
// CUDA array descriptor
|
||||
@@ -77,36 +78,35 @@ cudaArray *a_Src;
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
#include "imageDenoising_copy_kernel.cuh"
|
||||
#include "imageDenoising_knn_kernel.cuh"
|
||||
#include "imageDenoising_nlm_kernel.cuh"
|
||||
#include "imageDenoising_nlm2_kernel.cuh"
|
||||
#include "imageDenoising_nlm_kernel.cuh"
|
||||
|
||||
extern "C" cudaError_t CUDA_MallocArray(uchar4 **h_Src, int imageW,
|
||||
int imageH) {
|
||||
cudaError_t error;
|
||||
extern "C" cudaError_t CUDA_MallocArray(uchar4 **h_Src, int imageW, int imageH)
|
||||
{
|
||||
cudaError_t error;
|
||||
|
||||
error = cudaMallocArray(&a_Src, &uchar4tex, imageW, imageH);
|
||||
error = cudaMemcpy2DToArray(a_Src, 0, 0, *h_Src, sizeof(uchar4) * imageW,
|
||||
sizeof(uchar4) * imageW, imageH,
|
||||
cudaMemcpyHostToDevice);
|
||||
error = cudaMallocArray(&a_Src, &uchar4tex, imageW, imageH);
|
||||
error = cudaMemcpy2DToArray(
|
||||
a_Src, 0, 0, *h_Src, sizeof(uchar4) * imageW, sizeof(uchar4) * imageW, imageH, cudaMemcpyHostToDevice);
|
||||
|
||||
cudaResourceDesc texRes;
|
||||
memset(&texRes, 0, sizeof(cudaResourceDesc));
|
||||
cudaResourceDesc texRes;
|
||||
memset(&texRes, 0, sizeof(cudaResourceDesc));
|
||||
|
||||
texRes.resType = cudaResourceTypeArray;
|
||||
texRes.res.array.array = a_Src;
|
||||
texRes.resType = cudaResourceTypeArray;
|
||||
texRes.res.array.array = a_Src;
|
||||
|
||||
cudaTextureDesc texDescr;
|
||||
memset(&texDescr, 0, sizeof(cudaTextureDesc));
|
||||
cudaTextureDesc texDescr;
|
||||
memset(&texDescr, 0, sizeof(cudaTextureDesc));
|
||||
|
||||
texDescr.normalizedCoords = false;
|
||||
texDescr.filterMode = cudaFilterModeLinear;
|
||||
texDescr.addressMode[0] = cudaAddressModeWrap;
|
||||
texDescr.addressMode[1] = cudaAddressModeWrap;
|
||||
texDescr.readMode = cudaReadModeNormalizedFloat;
|
||||
texDescr.normalizedCoords = false;
|
||||
texDescr.filterMode = cudaFilterModeLinear;
|
||||
texDescr.addressMode[0] = cudaAddressModeWrap;
|
||||
texDescr.addressMode[1] = cudaAddressModeWrap;
|
||||
texDescr.readMode = cudaReadModeNormalizedFloat;
|
||||
|
||||
checkCudaErrors(cudaCreateTextureObject(&texImage, &texRes, &texDescr, NULL));
|
||||
checkCudaErrors(cudaCreateTextureObject(&texImage, &texRes, &texDescr, NULL));
|
||||
|
||||
return error;
|
||||
return error;
|
||||
}
|
||||
|
||||
extern "C" cudaError_t CUDA_FreeArray() { return cudaFreeArray(a_Src); }
|
||||
|
||||
@@ -33,20 +33,18 @@ typedef unsigned int TColor;
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Filter configuration
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
#define KNN_WINDOW_RADIUS 3
|
||||
#define NLM_WINDOW_RADIUS 3
|
||||
#define NLM_BLOCK_RADIUS 3
|
||||
#define KNN_WINDOW_AREA \
|
||||
((2 * KNN_WINDOW_RADIUS + 1) * (2 * KNN_WINDOW_RADIUS + 1))
|
||||
#define NLM_WINDOW_AREA \
|
||||
((2 * NLM_WINDOW_RADIUS + 1) * (2 * NLM_WINDOW_RADIUS + 1))
|
||||
#define KNN_WINDOW_RADIUS 3
|
||||
#define NLM_WINDOW_RADIUS 3
|
||||
#define NLM_BLOCK_RADIUS 3
|
||||
#define KNN_WINDOW_AREA ((2 * KNN_WINDOW_RADIUS + 1) * (2 * KNN_WINDOW_RADIUS + 1))
|
||||
#define NLM_WINDOW_AREA ((2 * NLM_WINDOW_RADIUS + 1) * (2 * NLM_WINDOW_RADIUS + 1))
|
||||
#define INV_KNN_WINDOW_AREA (1.0f / (float)KNN_WINDOW_AREA)
|
||||
#define INV_NLM_WINDOW_AREA (1.0f / (float)NLM_WINDOW_AREA)
|
||||
|
||||
#define KNN_WEIGHT_THRESHOLD 0.02f
|
||||
#define KNN_LERP_THRESHOLD 0.79f
|
||||
#define KNN_LERP_THRESHOLD 0.79f
|
||||
#define NLM_WEIGHT_THRESHOLD 0.10f
|
||||
#define NLM_LERP_THRESHOLD 0.10f
|
||||
#define NLM_LERP_THRESHOLD 0.10f
|
||||
|
||||
#define BLOCKDIM_X 8
|
||||
#define BLOCKDIM_Y 8
|
||||
@@ -59,8 +57,7 @@ typedef unsigned int TColor;
|
||||
#endif
|
||||
|
||||
// functions to load images
|
||||
extern "C" void LoadBMPFile(uchar4 **dst, int *width, int *height,
|
||||
const char *name);
|
||||
extern "C" void LoadBMPFile(uchar4 **dst, int *width, int *height, const char *name);
|
||||
|
||||
// CUDA wrapper functions for allocation/freeing texture arrays
|
||||
extern "C" cudaTextureObject_t texImage;
|
||||
@@ -69,21 +66,17 @@ extern "C" cudaError_t CUDA_MallocArray(uchar4 **h_Src, int imageW, int imageH);
|
||||
extern "C" cudaError_t CUDA_FreeArray();
|
||||
|
||||
// CUDA kernel functions
|
||||
extern "C" void cuda_Copy(TColor *d_dst, int imageW, int imageH,
|
||||
cudaTextureObject_t texImage);
|
||||
extern "C" void cuda_KNN(TColor *d_dst, int imageW, int imageH, float Noise,
|
||||
float lerpC, cudaTextureObject_t texImage);
|
||||
extern "C" void cuda_KNNdiag(TColor *d_dst, int imageW, int imageH, float Noise,
|
||||
float lerpC, cudaTextureObject_t texImage);
|
||||
extern "C" void cuda_NLM(TColor *d_dst, int imageW, int imageH, float Noise,
|
||||
float lerpC, cudaTextureObject_t texImage);
|
||||
extern "C" void cuda_NLMdiag(TColor *d_dst, int imageW, int imageH, float Noise,
|
||||
float lerpC, cudaTextureObject_t texImage);
|
||||
extern "C" void cuda_Copy(TColor *d_dst, int imageW, int imageH, cudaTextureObject_t texImage);
|
||||
extern "C" void cuda_KNN(TColor *d_dst, int imageW, int imageH, float Noise, float lerpC, cudaTextureObject_t texImage);
|
||||
extern "C" void
|
||||
cuda_KNNdiag(TColor *d_dst, int imageW, int imageH, float Noise, float lerpC, cudaTextureObject_t texImage);
|
||||
extern "C" void cuda_NLM(TColor *d_dst, int imageW, int imageH, float Noise, float lerpC, cudaTextureObject_t texImage);
|
||||
extern "C" void
|
||||
cuda_NLMdiag(TColor *d_dst, int imageW, int imageH, float Noise, float lerpC, cudaTextureObject_t texImage);
|
||||
|
||||
extern "C" void cuda_NLM2(TColor *d_dst, int imageW, int imageH, float Noise,
|
||||
float LerpC, cudaTextureObject_t texImage);
|
||||
extern "C" void cuda_NLM2diag(TColor *d_dst, int imageW, int imageH,
|
||||
float Noise, float LerpC,
|
||||
cudaTextureObject_t texImage);
|
||||
extern "C" void
|
||||
cuda_NLM2(TColor *d_dst, int imageW, int imageH, float Noise, float LerpC, cudaTextureObject_t texImage);
|
||||
extern "C" void
|
||||
cuda_NLM2diag(TColor *d_dst, int imageW, int imageH, float Noise, float LerpC, cudaTextureObject_t texImage);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -45,478 +45,387 @@
|
||||
#endif
|
||||
|
||||
// CUDA utilities and system includes
|
||||
#include <cuda_runtime.h>
|
||||
#include <cuda_gl_interop.h>
|
||||
#include <cuda_runtime.h>
|
||||
|
||||
// Includes
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "imageDenoising.h"
|
||||
|
||||
// includes, project
|
||||
#include <helper_functions.h> // includes for helper utility functions
|
||||
#include <helper_cuda.h> // includes for cuda error checking and initialization
|
||||
#include <helper_cuda.h> // includes for cuda error checking and initialization
|
||||
#include <helper_functions.h> // includes for helper utility functions
|
||||
|
||||
const char *sSDKsample = "CUDA ImageDenoising";
|
||||
|
||||
const char *filterMode[] = {"Passthrough", "KNN method", "NLM method",
|
||||
"Quick NLM(NLM2) method", NULL};
|
||||
const char *filterMode[] = {"Passthrough", "KNN method", "NLM method", "Quick NLM(NLM2) method", NULL};
|
||||
|
||||
// Define the files that are to be save and the reference images for validation
|
||||
const char *sOriginal[] = {"image_passthru.ppm", "image_knn.ppm",
|
||||
"image_nlm.ppm", "image_nlm2.ppm", NULL};
|
||||
const char *sOriginal[] = {"image_passthru.ppm", "image_knn.ppm", "image_nlm.ppm", "image_nlm2.ppm", NULL};
|
||||
|
||||
const char *sReference[] = {"ref_passthru.ppm", "ref_knn.ppm", "ref_nlm.ppm",
|
||||
"ref_nlm2.ppm", NULL};
|
||||
const char *sReference[] = {"ref_passthru.ppm", "ref_knn.ppm", "ref_nlm.ppm", "ref_nlm2.ppm", NULL};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Global data handlers and parameters
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// OpenGL PBO and texture "names"
|
||||
GLuint gl_PBO, gl_Tex;
|
||||
struct cudaGraphicsResource *cuda_pbo_resource; // handles OpenGL-CUDA exchange
|
||||
GLuint gl_PBO, gl_Tex;
|
||||
struct cudaGraphicsResource *cuda_pbo_resource; // handles OpenGL-CUDA exchange
|
||||
// Source image on the host side
|
||||
uchar4 *h_Src;
|
||||
int imageW, imageH;
|
||||
GLuint shader;
|
||||
int imageW, imageH;
|
||||
GLuint shader;
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Main program
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
int g_Kernel = 0;
|
||||
bool g_FPS = false;
|
||||
bool g_Diag = false;
|
||||
StopWatchInterface *timer = NULL;
|
||||
int g_Kernel = 0;
|
||||
bool g_FPS = false;
|
||||
bool g_Diag = false;
|
||||
StopWatchInterface *timer = NULL;
|
||||
|
||||
// Algorithms global parameters
|
||||
const float noiseStep = 0.025f;
|
||||
const float lerpStep = 0.025f;
|
||||
static float knnNoise = 0.32f;
|
||||
static float nlmNoise = 1.45f;
|
||||
static float lerpC = 0.2f;
|
||||
const float noiseStep = 0.025f;
|
||||
const float lerpStep = 0.025f;
|
||||
static float knnNoise = 0.32f;
|
||||
static float nlmNoise = 1.45f;
|
||||
static float lerpC = 0.2f;
|
||||
|
||||
const int frameN = 24;
|
||||
int frameCounter = 0;
|
||||
const int frameN = 24;
|
||||
int frameCounter = 0;
|
||||
|
||||
#define BUFFER_DATA(i) ((char *)0 + i)
|
||||
|
||||
// Auto-Verification Code
|
||||
const int frameCheckNumber = 4;
|
||||
int fpsCount = 0; // FPS count for averaging
|
||||
int fpsLimit = 1; // FPS limit for sampling
|
||||
unsigned int frameCount = 0;
|
||||
unsigned int g_TotalErrors = 0;
|
||||
const int frameCheckNumber = 4;
|
||||
int fpsCount = 0; // FPS count for averaging
|
||||
int fpsLimit = 1; // FPS limit for sampling
|
||||
unsigned int frameCount = 0;
|
||||
unsigned int g_TotalErrors = 0;
|
||||
|
||||
int *pArgc = NULL;
|
||||
int *pArgc = NULL;
|
||||
char **pArgv = NULL;
|
||||
|
||||
#define MAX_EPSILON_ERROR 5
|
||||
#define REFRESH_DELAY 10 // ms
|
||||
#define REFRESH_DELAY 10 // ms
|
||||
|
||||
void cleanup();
|
||||
|
||||
void computeFPS() {
|
||||
frameCount++;
|
||||
fpsCount++;
|
||||
void computeFPS()
|
||||
{
|
||||
frameCount++;
|
||||
fpsCount++;
|
||||
|
||||
if (fpsCount == fpsLimit) {
|
||||
char fps[256];
|
||||
float ifps = 1.f / (sdkGetAverageTimerValue(&timer) / 1000.f);
|
||||
sprintf(fps, "<%s>: %3.1f fps", filterMode[g_Kernel], ifps);
|
||||
if (fpsCount == fpsLimit) {
|
||||
char fps[256];
|
||||
float ifps = 1.f / (sdkGetAverageTimerValue(&timer) / 1000.f);
|
||||
sprintf(fps, "<%s>: %3.1f fps", filterMode[g_Kernel], ifps);
|
||||
|
||||
glutSetWindowTitle(fps);
|
||||
fpsCount = 0;
|
||||
glutSetWindowTitle(fps);
|
||||
fpsCount = 0;
|
||||
|
||||
// fpsLimit = (int)MAX(ifps, 1.f);
|
||||
sdkResetTimer(&timer);
|
||||
}
|
||||
// fpsLimit = (int)MAX(ifps, 1.f);
|
||||
sdkResetTimer(&timer);
|
||||
}
|
||||
}
|
||||
|
||||
void runImageFilters(TColor *d_dst) {
|
||||
switch (g_Kernel) {
|
||||
void runImageFilters(TColor *d_dst)
|
||||
{
|
||||
switch (g_Kernel) {
|
||||
case 0:
|
||||
cuda_Copy(d_dst, imageW, imageH, texImage);
|
||||
break;
|
||||
cuda_Copy(d_dst, imageW, imageH, texImage);
|
||||
break;
|
||||
|
||||
case 1:
|
||||
if (!g_Diag) {
|
||||
cuda_KNN(d_dst, imageW, imageH, 1.0f / (knnNoise * knnNoise), lerpC,
|
||||
texImage);
|
||||
} else {
|
||||
cuda_KNNdiag(d_dst, imageW, imageH, 1.0f / (knnNoise * knnNoise), lerpC,
|
||||
texImage);
|
||||
}
|
||||
if (!g_Diag) {
|
||||
cuda_KNN(d_dst, imageW, imageH, 1.0f / (knnNoise * knnNoise), lerpC, texImage);
|
||||
}
|
||||
else {
|
||||
cuda_KNNdiag(d_dst, imageW, imageH, 1.0f / (knnNoise * knnNoise), lerpC, texImage);
|
||||
}
|
||||
|
||||
break;
|
||||
break;
|
||||
|
||||
case 2:
|
||||
if (!g_Diag) {
|
||||
cuda_NLM(d_dst, imageW, imageH, 1.0f / (nlmNoise * nlmNoise), lerpC,
|
||||
texImage);
|
||||
} else {
|
||||
cuda_NLMdiag(d_dst, imageW, imageH, 1.0f / (nlmNoise * nlmNoise), lerpC,
|
||||
texImage);
|
||||
}
|
||||
if (!g_Diag) {
|
||||
cuda_NLM(d_dst, imageW, imageH, 1.0f / (nlmNoise * nlmNoise), lerpC, texImage);
|
||||
}
|
||||
else {
|
||||
cuda_NLMdiag(d_dst, imageW, imageH, 1.0f / (nlmNoise * nlmNoise), lerpC, texImage);
|
||||
}
|
||||
|
||||
break;
|
||||
break;
|
||||
|
||||
case 3:
|
||||
if (!g_Diag) {
|
||||
cuda_NLM2(d_dst, imageW, imageH, 1.0f / (nlmNoise * nlmNoise), lerpC,
|
||||
texImage);
|
||||
} else {
|
||||
cuda_NLM2diag(d_dst, imageW, imageH, 1.0f / (nlmNoise * nlmNoise),
|
||||
lerpC, texImage);
|
||||
}
|
||||
if (!g_Diag) {
|
||||
cuda_NLM2(d_dst, imageW, imageH, 1.0f / (nlmNoise * nlmNoise), lerpC, texImage);
|
||||
}
|
||||
else {
|
||||
cuda_NLM2diag(d_dst, imageW, imageH, 1.0f / (nlmNoise * nlmNoise), lerpC, texImage);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
getLastCudaError("Filtering kernel execution failed.\n");
|
||||
}
|
||||
|
||||
void displayFunc(void) {
|
||||
sdkStartTimer(&timer);
|
||||
TColor *d_dst = NULL;
|
||||
size_t num_bytes;
|
||||
|
||||
if (frameCounter++ == 0) {
|
||||
sdkResetTimer(&timer);
|
||||
}
|
||||
|
||||
checkCudaErrors(cudaGraphicsMapResources(1, &cuda_pbo_resource, 0));
|
||||
getLastCudaError("cudaGraphicsMapResources failed");
|
||||
checkCudaErrors(cudaGraphicsResourceGetMappedPointer(
|
||||
(void **)&d_dst, &num_bytes, cuda_pbo_resource));
|
||||
getLastCudaError("cudaGraphicsResourceGetMappedPointer failed");
|
||||
|
||||
runImageFilters(d_dst);
|
||||
|
||||
checkCudaErrors(cudaGraphicsUnmapResources(1, &cuda_pbo_resource, 0));
|
||||
|
||||
// Common display code path
|
||||
{
|
||||
glClear(GL_COLOR_BUFFER_BIT);
|
||||
|
||||
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, imageW, imageH, GL_RGBA,
|
||||
GL_UNSIGNED_BYTE, BUFFER_DATA(0));
|
||||
glBegin(GL_TRIANGLES);
|
||||
glTexCoord2f(0, 0);
|
||||
glVertex2f(-1, -1);
|
||||
glTexCoord2f(2, 0);
|
||||
glVertex2f(+3, -1);
|
||||
glTexCoord2f(0, 2);
|
||||
glVertex2f(-1, +3);
|
||||
glEnd();
|
||||
glFinish();
|
||||
}
|
||||
|
||||
if (frameCounter == frameN) {
|
||||
frameCounter = 0;
|
||||
|
||||
if (g_FPS) {
|
||||
printf("FPS: %3.1f\n", frameN / (sdkGetTimerValue(&timer) * 0.001));
|
||||
g_FPS = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
glutSwapBuffers();
|
||||
glutReportErrors();
|
||||
|
||||
sdkStopTimer(&timer);
|
||||
|
||||
computeFPS();
|
||||
getLastCudaError("Filtering kernel execution failed.\n");
|
||||
}
|
||||
|
||||
void timerEvent(int value) {
|
||||
if (glutGetWindow()) {
|
||||
glutPostRedisplay();
|
||||
glutTimerFunc(REFRESH_DELAY, timerEvent, 0);
|
||||
}
|
||||
void displayFunc(void)
|
||||
{
|
||||
sdkStartTimer(&timer);
|
||||
TColor *d_dst = NULL;
|
||||
size_t num_bytes;
|
||||
|
||||
if (frameCounter++ == 0) {
|
||||
sdkResetTimer(&timer);
|
||||
}
|
||||
|
||||
checkCudaErrors(cudaGraphicsMapResources(1, &cuda_pbo_resource, 0));
|
||||
getLastCudaError("cudaGraphicsMapResources failed");
|
||||
checkCudaErrors(cudaGraphicsResourceGetMappedPointer((void **)&d_dst, &num_bytes, cuda_pbo_resource));
|
||||
getLastCudaError("cudaGraphicsResourceGetMappedPointer failed");
|
||||
|
||||
runImageFilters(d_dst);
|
||||
|
||||
checkCudaErrors(cudaGraphicsUnmapResources(1, &cuda_pbo_resource, 0));
|
||||
|
||||
// Common display code path
|
||||
{
|
||||
glClear(GL_COLOR_BUFFER_BIT);
|
||||
|
||||
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, imageW, imageH, GL_RGBA, GL_UNSIGNED_BYTE, BUFFER_DATA(0));
|
||||
glBegin(GL_TRIANGLES);
|
||||
glTexCoord2f(0, 0);
|
||||
glVertex2f(-1, -1);
|
||||
glTexCoord2f(2, 0);
|
||||
glVertex2f(+3, -1);
|
||||
glTexCoord2f(0, 2);
|
||||
glVertex2f(-1, +3);
|
||||
glEnd();
|
||||
glFinish();
|
||||
}
|
||||
|
||||
if (frameCounter == frameN) {
|
||||
frameCounter = 0;
|
||||
|
||||
if (g_FPS) {
|
||||
printf("FPS: %3.1f\n", frameN / (sdkGetTimerValue(&timer) * 0.001));
|
||||
g_FPS = false;
|
||||
}
|
||||
}
|
||||
|
||||
glutSwapBuffers();
|
||||
glutReportErrors();
|
||||
|
||||
sdkStopTimer(&timer);
|
||||
|
||||
computeFPS();
|
||||
}
|
||||
|
||||
void keyboard(unsigned char k, int /*x*/, int /*y*/) {
|
||||
switch (k) {
|
||||
void timerEvent(int value)
|
||||
{
|
||||
if (glutGetWindow()) {
|
||||
glutPostRedisplay();
|
||||
glutTimerFunc(REFRESH_DELAY, timerEvent, 0);
|
||||
}
|
||||
}
|
||||
|
||||
void keyboard(unsigned char k, int /*x*/, int /*y*/)
|
||||
{
|
||||
switch (k) {
|
||||
case 27:
|
||||
case 'q':
|
||||
case 'Q':
|
||||
#if defined(__APPLE__) || defined(MACOSX)
|
||||
exit(EXIT_SUCCESS);
|
||||
exit(EXIT_SUCCESS);
|
||||
#else
|
||||
glutDestroyWindow(glutGetWindow());
|
||||
return;
|
||||
glutDestroyWindow(glutGetWindow());
|
||||
return;
|
||||
#endif
|
||||
|
||||
case '1':
|
||||
printf("Passthrough.\n");
|
||||
g_Kernel = 0;
|
||||
break;
|
||||
printf("Passthrough.\n");
|
||||
g_Kernel = 0;
|
||||
break;
|
||||
|
||||
case '2':
|
||||
printf("KNN method \n");
|
||||
g_Kernel = 1;
|
||||
break;
|
||||
printf("KNN method \n");
|
||||
g_Kernel = 1;
|
||||
break;
|
||||
|
||||
case '3':
|
||||
printf("NLM method\n");
|
||||
g_Kernel = 2;
|
||||
break;
|
||||
printf("NLM method\n");
|
||||
g_Kernel = 2;
|
||||
break;
|
||||
|
||||
case '4':
|
||||
printf("Quick NLM(NLM2) method\n");
|
||||
g_Kernel = 3;
|
||||
break;
|
||||
printf("Quick NLM(NLM2) method\n");
|
||||
g_Kernel = 3;
|
||||
break;
|
||||
|
||||
case '*':
|
||||
printf(g_Diag ? "LERP highlighting mode.\n" : "Normal mode.\n");
|
||||
g_Diag = !g_Diag;
|
||||
break;
|
||||
printf(g_Diag ? "LERP highlighting mode.\n" : "Normal mode.\n");
|
||||
g_Diag = !g_Diag;
|
||||
break;
|
||||
|
||||
case 'n':
|
||||
printf("Decrease noise level.\n");
|
||||
knnNoise -= noiseStep;
|
||||
nlmNoise -= noiseStep;
|
||||
break;
|
||||
printf("Decrease noise level.\n");
|
||||
knnNoise -= noiseStep;
|
||||
nlmNoise -= noiseStep;
|
||||
break;
|
||||
|
||||
case 'N':
|
||||
printf("Increase noise level.\n");
|
||||
knnNoise += noiseStep;
|
||||
nlmNoise += noiseStep;
|
||||
break;
|
||||
printf("Increase noise level.\n");
|
||||
knnNoise += noiseStep;
|
||||
nlmNoise += noiseStep;
|
||||
break;
|
||||
|
||||
case 'l':
|
||||
printf("Decrease LERP quotient.\n");
|
||||
lerpC = MAX(lerpC - lerpStep, 0.0f);
|
||||
break;
|
||||
printf("Decrease LERP quotient.\n");
|
||||
lerpC = MAX(lerpC - lerpStep, 0.0f);
|
||||
break;
|
||||
|
||||
case 'L':
|
||||
printf("Increase LERP quotient.\n");
|
||||
lerpC = MIN(lerpC + lerpStep, 1.0f);
|
||||
break;
|
||||
printf("Increase LERP quotient.\n");
|
||||
lerpC = MIN(lerpC + lerpStep, 1.0f);
|
||||
break;
|
||||
|
||||
case 'f':
|
||||
case 'F':
|
||||
g_FPS = true;
|
||||
break;
|
||||
g_FPS = true;
|
||||
break;
|
||||
|
||||
case '?':
|
||||
printf("lerpC = %5.5f\n", lerpC);
|
||||
printf("knnNoise = %5.5f\n", knnNoise);
|
||||
printf("nlmNoise = %5.5f\n", nlmNoise);
|
||||
break;
|
||||
}
|
||||
printf("lerpC = %5.5f\n", lerpC);
|
||||
printf("knnNoise = %5.5f\n", knnNoise);
|
||||
printf("nlmNoise = %5.5f\n", nlmNoise);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
int initGL(int *argc, char **argv) {
|
||||
printf("Initializing GLUT...\n");
|
||||
glutInit(argc, argv);
|
||||
glutInitDisplayMode(GLUT_RGBA | GLUT_DOUBLE);
|
||||
glutInitWindowSize(imageW, imageH);
|
||||
glutInitWindowPosition(512 - imageW / 2, 384 - imageH / 2);
|
||||
glutCreateWindow(argv[0]);
|
||||
glutDisplayFunc(displayFunc);
|
||||
glutKeyboardFunc(keyboard);
|
||||
glutTimerFunc(REFRESH_DELAY, timerEvent, 0);
|
||||
printf("OpenGL window created.\n");
|
||||
int initGL(int *argc, char **argv)
|
||||
{
|
||||
printf("Initializing GLUT...\n");
|
||||
glutInit(argc, argv);
|
||||
glutInitDisplayMode(GLUT_RGBA | GLUT_DOUBLE);
|
||||
glutInitWindowSize(imageW, imageH);
|
||||
glutInitWindowPosition(512 - imageW / 2, 384 - imageH / 2);
|
||||
glutCreateWindow(argv[0]);
|
||||
glutDisplayFunc(displayFunc);
|
||||
glutKeyboardFunc(keyboard);
|
||||
glutTimerFunc(REFRESH_DELAY, timerEvent, 0);
|
||||
printf("OpenGL window created.\n");
|
||||
|
||||
#if defined(__APPLE__) || defined(MACOSX)
|
||||
atexit(cleanup);
|
||||
atexit(cleanup);
|
||||
#else
|
||||
glutCloseFunc(cleanup);
|
||||
glutCloseFunc(cleanup);
|
||||
#endif
|
||||
|
||||
if (!isGLVersionSupported(1, 5) ||
|
||||
!areGLExtensionsSupported(
|
||||
"GL_ARB_vertex_buffer_object GL_ARB_pixel_buffer_object")) {
|
||||
fprintf(stderr, "Error: failed to get minimal extensions for demo\n");
|
||||
fprintf(stderr, "This sample requires:\n");
|
||||
fprintf(stderr, " OpenGL version 1.5\n");
|
||||
fprintf(stderr, " GL_ARB_vertex_buffer_object\n");
|
||||
fprintf(stderr, " GL_ARB_pixel_buffer_object\n");
|
||||
fflush(stderr);
|
||||
return false;
|
||||
}
|
||||
if (!isGLVersionSupported(1, 5)
|
||||
|| !areGLExtensionsSupported("GL_ARB_vertex_buffer_object GL_ARB_pixel_buffer_object")) {
|
||||
fprintf(stderr, "Error: failed to get minimal extensions for demo\n");
|
||||
fprintf(stderr, "This sample requires:\n");
|
||||
fprintf(stderr, " OpenGL version 1.5\n");
|
||||
fprintf(stderr, " GL_ARB_vertex_buffer_object\n");
|
||||
fprintf(stderr, " GL_ARB_pixel_buffer_object\n");
|
||||
fflush(stderr);
|
||||
return false;
|
||||
}
|
||||
|
||||
return 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
// shader for displaying floating-point texture
|
||||
static const char *shader_code =
|
||||
"!!ARBfp1.0\n"
|
||||
"TEX result.color, fragment.texcoord, texture[0], 2D; \n"
|
||||
"END";
|
||||
static const char *shader_code = "!!ARBfp1.0\n"
|
||||
"TEX result.color, fragment.texcoord, texture[0], 2D; \n"
|
||||
"END";
|
||||
|
||||
GLuint compileASMShader(GLenum program_type, const char *code) {
|
||||
GLuint program_id;
|
||||
glGenProgramsARB(1, &program_id);
|
||||
glBindProgramARB(program_type, program_id);
|
||||
glProgramStringARB(program_type, GL_PROGRAM_FORMAT_ASCII_ARB,
|
||||
(GLsizei)strlen(code), (GLubyte *)code);
|
||||
GLuint compileASMShader(GLenum program_type, const char *code)
|
||||
{
|
||||
GLuint program_id;
|
||||
glGenProgramsARB(1, &program_id);
|
||||
glBindProgramARB(program_type, program_id);
|
||||
glProgramStringARB(program_type, GL_PROGRAM_FORMAT_ASCII_ARB, (GLsizei)strlen(code), (GLubyte *)code);
|
||||
|
||||
GLint error_pos;
|
||||
glGetIntegerv(GL_PROGRAM_ERROR_POSITION_ARB, &error_pos);
|
||||
GLint error_pos;
|
||||
glGetIntegerv(GL_PROGRAM_ERROR_POSITION_ARB, &error_pos);
|
||||
|
||||
if (error_pos != -1) {
|
||||
const GLubyte *error_string;
|
||||
error_string = glGetString(GL_PROGRAM_ERROR_STRING_ARB);
|
||||
fprintf(stderr, "Program error at position: %d\n%s\n", (int)error_pos,
|
||||
error_string);
|
||||
return 0;
|
||||
}
|
||||
if (error_pos != -1) {
|
||||
const GLubyte *error_string;
|
||||
error_string = glGetString(GL_PROGRAM_ERROR_STRING_ARB);
|
||||
fprintf(stderr, "Program error at position: %d\n%s\n", (int)error_pos, error_string);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return program_id;
|
||||
return program_id;
|
||||
}
|
||||
|
||||
void initOpenGLBuffers() {
|
||||
printf("Creating GL texture...\n");
|
||||
glEnable(GL_TEXTURE_2D);
|
||||
glGenTextures(1, &gl_Tex);
|
||||
glBindTexture(GL_TEXTURE_2D, gl_Tex);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, imageW, imageH, 0, GL_RGBA,
|
||||
GL_UNSIGNED_BYTE, h_Src);
|
||||
printf("Texture created.\n");
|
||||
void initOpenGLBuffers()
|
||||
{
|
||||
printf("Creating GL texture...\n");
|
||||
glEnable(GL_TEXTURE_2D);
|
||||
glGenTextures(1, &gl_Tex);
|
||||
glBindTexture(GL_TEXTURE_2D, gl_Tex);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, imageW, imageH, 0, GL_RGBA, GL_UNSIGNED_BYTE, h_Src);
|
||||
printf("Texture created.\n");
|
||||
|
||||
printf("Creating PBO...\n");
|
||||
glGenBuffers(1, &gl_PBO);
|
||||
glBindBuffer(GL_PIXEL_UNPACK_BUFFER_ARB, gl_PBO);
|
||||
glBufferData(GL_PIXEL_UNPACK_BUFFER_ARB, imageW * imageH * 4, h_Src,
|
||||
GL_STREAM_COPY);
|
||||
// While a PBO is registered to CUDA, it can't be used
|
||||
// as the destination for OpenGL drawing calls.
|
||||
// But in our particular case OpenGL is only used
|
||||
// to display the content of the PBO, specified by CUDA kernels,
|
||||
// so we need to register/unregister it only once.
|
||||
// DEPRECATED: checkCudaErrors(cudaGLRegisterBufferObject(gl_PBO) );
|
||||
checkCudaErrors(cudaGraphicsGLRegisterBuffer(
|
||||
&cuda_pbo_resource, gl_PBO, cudaGraphicsMapFlagsWriteDiscard));
|
||||
GLenum gl_error = glGetError();
|
||||
printf("Creating PBO...\n");
|
||||
glGenBuffers(1, &gl_PBO);
|
||||
glBindBuffer(GL_PIXEL_UNPACK_BUFFER_ARB, gl_PBO);
|
||||
glBufferData(GL_PIXEL_UNPACK_BUFFER_ARB, imageW * imageH * 4, h_Src, GL_STREAM_COPY);
|
||||
// While a PBO is registered to CUDA, it can't be used
|
||||
// as the destination for OpenGL drawing calls.
|
||||
// But in our particular case OpenGL is only used
|
||||
// to display the content of the PBO, specified by CUDA kernels,
|
||||
// so we need to register/unregister it only once.
|
||||
// DEPRECATED: checkCudaErrors(cudaGLRegisterBufferObject(gl_PBO) );
|
||||
checkCudaErrors(cudaGraphicsGLRegisterBuffer(&cuda_pbo_resource, gl_PBO, cudaGraphicsMapFlagsWriteDiscard));
|
||||
GLenum gl_error = glGetError();
|
||||
|
||||
if (gl_error != GL_NO_ERROR) {
|
||||
if (gl_error != GL_NO_ERROR) {
|
||||
#if defined(WIN32) || defined(_WIN32) || defined(WIN64) || defined(_WIN64)
|
||||
char tmpStr[512];
|
||||
// NOTE: "%s(%i) : " allows Visual Studio to directly jump to the file at
|
||||
// the right line when the user double clicks on the error line in the
|
||||
// Output pane. Like any compile error.
|
||||
sprintf_s(tmpStr, 255, "\n%s(%i) : GL Error : %s\n\n", __FILE__, __LINE__,
|
||||
gluErrorString(gl_error));
|
||||
OutputDebugString(tmpStr);
|
||||
char tmpStr[512];
|
||||
// NOTE: "%s(%i) : " allows Visual Studio to directly jump to the file at
|
||||
// the right line when the user double clicks on the error line in the
|
||||
// Output pane. Like any compile error.
|
||||
sprintf_s(tmpStr, 255, "\n%s(%i) : GL Error : %s\n\n", __FILE__, __LINE__, gluErrorString(gl_error));
|
||||
OutputDebugString(tmpStr);
|
||||
#endif
|
||||
fprintf(stderr, "GL Error in file '%s' in line %d :\n", __FILE__, __LINE__);
|
||||
fprintf(stderr, "%s\n", gluErrorString(gl_error));
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
printf("PBO created.\n");
|
||||
|
||||
// load shader program
|
||||
shader = compileASMShader(GL_FRAGMENT_PROGRAM_ARB, shader_code);
|
||||
}
|
||||
|
||||
void cleanup() {
|
||||
free(h_Src);
|
||||
checkCudaErrors(CUDA_FreeArray());
|
||||
checkCudaErrors(cudaGraphicsUnregisterResource(cuda_pbo_resource));
|
||||
|
||||
glDeleteProgramsARB(1, &shader);
|
||||
|
||||
sdkDeleteTimer(&timer);
|
||||
}
|
||||
|
||||
void runAutoTest(int argc, char **argv, const char *filename,
|
||||
int kernel_param) {
|
||||
printf("[%s] - (automated testing w/ readback)\n", sSDKsample);
|
||||
|
||||
int devID = findCudaDevice(argc, (const char **)argv);
|
||||
|
||||
// First load the image, so we know what the size of the image (imageW and
|
||||
// imageH)
|
||||
printf("Allocating host and CUDA memory and loading image file...\n");
|
||||
const char *image_path = sdkFindFilePath("portrait_noise.bmp", argv[0]);
|
||||
|
||||
if (image_path == NULL) {
|
||||
printf(
|
||||
"imageDenoisingGL was unable to find and load image file "
|
||||
"<portrait_noise.bmp>.\nExiting...\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
LoadBMPFile(&h_Src, &imageW, &imageH, image_path);
|
||||
printf("Data init done.\n");
|
||||
|
||||
checkCudaErrors(CUDA_MallocArray(&h_Src, imageW, imageH));
|
||||
|
||||
TColor *d_dst = NULL;
|
||||
unsigned char *h_dst = NULL;
|
||||
checkCudaErrors(
|
||||
cudaMalloc((void **)&d_dst, imageW * imageH * sizeof(TColor)));
|
||||
h_dst = (unsigned char *)malloc(imageH * imageW * 4);
|
||||
|
||||
{
|
||||
g_Kernel = kernel_param;
|
||||
printf("[AutoTest]: %s <%s>\n", sSDKsample, filterMode[g_Kernel]);
|
||||
|
||||
runImageFilters(d_dst);
|
||||
|
||||
checkCudaErrors(cudaDeviceSynchronize());
|
||||
|
||||
checkCudaErrors(cudaMemcpy(h_dst, d_dst, imageW * imageH * sizeof(TColor),
|
||||
cudaMemcpyDeviceToHost));
|
||||
sdkSavePPM4ub(filename, h_dst, imageW, imageH);
|
||||
}
|
||||
|
||||
checkCudaErrors(CUDA_FreeArray());
|
||||
free(h_Src);
|
||||
|
||||
checkCudaErrors(cudaFree(d_dst));
|
||||
free(h_dst);
|
||||
|
||||
printf("\n[%s] -> Kernel %d, Saved: %s\n", sSDKsample, kernel_param,
|
||||
filename);
|
||||
|
||||
exit(g_TotalErrors == 0 ? EXIT_SUCCESS : EXIT_FAILURE);
|
||||
}
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
char *dump_file = NULL;
|
||||
|
||||
#if defined(__linux__)
|
||||
setenv("DISPLAY", ":0", 0);
|
||||
#endif
|
||||
|
||||
pArgc = &argc;
|
||||
pArgv = argv;
|
||||
|
||||
printf("%s Starting...\n\n", sSDKsample);
|
||||
|
||||
if (checkCmdLineFlag(argc, (const char **)argv, "file")) {
|
||||
getCmdLineArgumentString(argc, (const char **)argv, "file",
|
||||
(char **)&dump_file);
|
||||
|
||||
int kernel = 1;
|
||||
|
||||
if (checkCmdLineFlag(argc, (const char **)argv, "kernel")) {
|
||||
kernel = getCmdLineArgumentInt(argc, (const char **)argv, "kernel");
|
||||
fprintf(stderr, "GL Error in file '%s' in line %d :\n", __FILE__, __LINE__);
|
||||
fprintf(stderr, "%s\n", gluErrorString(gl_error));
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
runAutoTest(argc, argv, dump_file, kernel);
|
||||
} else {
|
||||
printf("[%s]\n", sSDKsample);
|
||||
printf("PBO created.\n");
|
||||
|
||||
// use command-line specified CUDA device, otherwise use device with highest
|
||||
// Gflops/s
|
||||
if (checkCmdLineFlag(argc, (const char **)argv, "device")) {
|
||||
printf("[%s]\n", argv[0]);
|
||||
printf(" Does not explicitly support -device=n in OpenGL mode\n");
|
||||
printf(" To use -device=n, the sample must be running w/o OpenGL\n\n");
|
||||
printf(" > %s -device=n -qatest\n", argv[0]);
|
||||
printf("exiting...\n");
|
||||
exit(EXIT_SUCCESS);
|
||||
}
|
||||
// load shader program
|
||||
shader = compileASMShader(GL_FRAGMENT_PROGRAM_ARB, shader_code);
|
||||
}
|
||||
|
||||
void cleanup()
|
||||
{
|
||||
free(h_Src);
|
||||
checkCudaErrors(CUDA_FreeArray());
|
||||
checkCudaErrors(cudaGraphicsUnregisterResource(cuda_pbo_resource));
|
||||
|
||||
glDeleteProgramsARB(1, &shader);
|
||||
|
||||
sdkDeleteTimer(&timer);
|
||||
}
|
||||
|
||||
void runAutoTest(int argc, char **argv, const char *filename, int kernel_param)
|
||||
{
|
||||
printf("[%s] - (automated testing w/ readback)\n", sSDKsample);
|
||||
|
||||
int devID = findCudaDevice(argc, (const char **)argv);
|
||||
|
||||
// First load the image, so we know what the size of the image (imageW and
|
||||
// imageH)
|
||||
@@ -524,37 +433,117 @@ int main(int argc, char **argv) {
|
||||
const char *image_path = sdkFindFilePath("portrait_noise.bmp", argv[0]);
|
||||
|
||||
if (image_path == NULL) {
|
||||
printf(
|
||||
"imageDenoisingGL was unable to find and load image file "
|
||||
"<portrait_noise.bmp>.\nExiting...\n");
|
||||
exit(EXIT_FAILURE);
|
||||
printf("imageDenoisingGL was unable to find and load image file "
|
||||
"<portrait_noise.bmp>.\nExiting...\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
LoadBMPFile(&h_Src, &imageW, &imageH, image_path);
|
||||
printf("Data init done.\n");
|
||||
|
||||
initGL(&argc, argv);
|
||||
findCudaDevice(argc, (const char **)argv);
|
||||
|
||||
checkCudaErrors(CUDA_MallocArray(&h_Src, imageW, imageH));
|
||||
|
||||
initOpenGLBuffers();
|
||||
}
|
||||
TColor *d_dst = NULL;
|
||||
unsigned char *h_dst = NULL;
|
||||
checkCudaErrors(cudaMalloc((void **)&d_dst, imageW * imageH * sizeof(TColor)));
|
||||
h_dst = (unsigned char *)malloc(imageH * imageW * 4);
|
||||
|
||||
printf("Starting GLUT main loop...\n");
|
||||
printf("Press [1] to view noisy image\n");
|
||||
printf("Press [2] to view image restored with knn filter\n");
|
||||
printf("Press [3] to view image restored with nlm filter\n");
|
||||
printf("Press [4] to view image restored with modified nlm filter\n");
|
||||
printf(
|
||||
"Press [*] to view smooth/edgy areas [RED/BLUE] Ct's when a filter is "
|
||||
"active\n");
|
||||
printf("Press [f] to print frame rate\n");
|
||||
printf("Press [?] to print Noise and Lerp Ct's\n");
|
||||
printf("Press [q] to exit\n");
|
||||
{
|
||||
g_Kernel = kernel_param;
|
||||
printf("[AutoTest]: %s <%s>\n", sSDKsample, filterMode[g_Kernel]);
|
||||
|
||||
sdkCreateTimer(&timer);
|
||||
sdkStartTimer(&timer);
|
||||
runImageFilters(d_dst);
|
||||
|
||||
glutMainLoop();
|
||||
checkCudaErrors(cudaDeviceSynchronize());
|
||||
|
||||
checkCudaErrors(cudaMemcpy(h_dst, d_dst, imageW * imageH * sizeof(TColor), cudaMemcpyDeviceToHost));
|
||||
sdkSavePPM4ub(filename, h_dst, imageW, imageH);
|
||||
}
|
||||
|
||||
checkCudaErrors(CUDA_FreeArray());
|
||||
free(h_Src);
|
||||
|
||||
checkCudaErrors(cudaFree(d_dst));
|
||||
free(h_dst);
|
||||
|
||||
printf("\n[%s] -> Kernel %d, Saved: %s\n", sSDKsample, kernel_param, filename);
|
||||
|
||||
exit(g_TotalErrors == 0 ? EXIT_SUCCESS : EXIT_FAILURE);
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
char *dump_file = NULL;
|
||||
|
||||
#if defined(__linux__)
|
||||
setenv("DISPLAY", ":0", 0);
|
||||
#endif
|
||||
|
||||
pArgc = &argc;
|
||||
pArgv = argv;
|
||||
|
||||
printf("%s Starting...\n\n", sSDKsample);
|
||||
|
||||
if (checkCmdLineFlag(argc, (const char **)argv, "file")) {
|
||||
getCmdLineArgumentString(argc, (const char **)argv, "file", (char **)&dump_file);
|
||||
|
||||
int kernel = 1;
|
||||
|
||||
if (checkCmdLineFlag(argc, (const char **)argv, "kernel")) {
|
||||
kernel = getCmdLineArgumentInt(argc, (const char **)argv, "kernel");
|
||||
}
|
||||
|
||||
runAutoTest(argc, argv, dump_file, kernel);
|
||||
}
|
||||
else {
|
||||
printf("[%s]\n", sSDKsample);
|
||||
|
||||
// use command-line specified CUDA device, otherwise use device with highest
|
||||
// Gflops/s
|
||||
if (checkCmdLineFlag(argc, (const char **)argv, "device")) {
|
||||
printf("[%s]\n", argv[0]);
|
||||
printf(" Does not explicitly support -device=n in OpenGL mode\n");
|
||||
printf(" To use -device=n, the sample must be running w/o OpenGL\n\n");
|
||||
printf(" > %s -device=n -qatest\n", argv[0]);
|
||||
printf("exiting...\n");
|
||||
exit(EXIT_SUCCESS);
|
||||
}
|
||||
|
||||
// First load the image, so we know what the size of the image (imageW and
|
||||
// imageH)
|
||||
printf("Allocating host and CUDA memory and loading image file...\n");
|
||||
const char *image_path = sdkFindFilePath("portrait_noise.bmp", argv[0]);
|
||||
|
||||
if (image_path == NULL) {
|
||||
printf("imageDenoisingGL was unable to find and load image file "
|
||||
"<portrait_noise.bmp>.\nExiting...\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
LoadBMPFile(&h_Src, &imageW, &imageH, image_path);
|
||||
printf("Data init done.\n");
|
||||
|
||||
initGL(&argc, argv);
|
||||
findCudaDevice(argc, (const char **)argv);
|
||||
|
||||
checkCudaErrors(CUDA_MallocArray(&h_Src, imageW, imageH));
|
||||
|
||||
initOpenGLBuffers();
|
||||
}
|
||||
|
||||
printf("Starting GLUT main loop...\n");
|
||||
printf("Press [1] to view noisy image\n");
|
||||
printf("Press [2] to view image restored with knn filter\n");
|
||||
printf("Press [3] to view image restored with nlm filter\n");
|
||||
printf("Press [4] to view image restored with modified nlm filter\n");
|
||||
printf("Press [*] to view smooth/edgy areas [RED/BLUE] Ct's when a filter is "
|
||||
"active\n");
|
||||
printf("Press [f] to print frame rate\n");
|
||||
printf("Press [?] to print Noise and Lerp Ct's\n");
|
||||
printf("Press [q] to exit\n");
|
||||
|
||||
sdkCreateTimer(&timer);
|
||||
sdkStartTimer(&timer);
|
||||
|
||||
glutMainLoop();
|
||||
}
|
||||
|
||||
@@ -25,24 +25,24 @@
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
__global__ void Copy(TColor *dst, int imageW, int imageH,
|
||||
cudaTextureObject_t texImage) {
|
||||
const int ix = blockDim.x * blockIdx.x + threadIdx.x;
|
||||
const int iy = blockDim.y * blockIdx.y + threadIdx.y;
|
||||
// Add half of a texel to always address exact texel centers
|
||||
const float x = (float)ix + 0.5f;
|
||||
const float y = (float)iy + 0.5f;
|
||||
__global__ void Copy(TColor *dst, int imageW, int imageH, cudaTextureObject_t texImage)
|
||||
{
|
||||
const int ix = blockDim.x * blockIdx.x + threadIdx.x;
|
||||
const int iy = blockDim.y * blockIdx.y + threadIdx.y;
|
||||
// Add half of a texel to always address exact texel centers
|
||||
const float x = (float)ix + 0.5f;
|
||||
const float y = (float)iy + 0.5f;
|
||||
|
||||
if (ix < imageW && iy < imageH) {
|
||||
float4 fresult = tex2D<float4>(texImage, x, y);
|
||||
dst[imageW * iy + ix] = make_color(fresult.x, fresult.y, fresult.z, 0);
|
||||
}
|
||||
if (ix < imageW && iy < imageH) {
|
||||
float4 fresult = tex2D<float4>(texImage, x, y);
|
||||
dst[imageW * iy + ix] = make_color(fresult.x, fresult.y, fresult.z, 0);
|
||||
}
|
||||
}
|
||||
|
||||
extern "C" void cuda_Copy(TColor *d_dst, int imageW, int imageH,
|
||||
cudaTextureObject_t texImage) {
|
||||
dim3 threads(BLOCKDIM_X, BLOCKDIM_Y);
|
||||
dim3 grid(iDivUp(imageW, BLOCKDIM_X), iDivUp(imageH, BLOCKDIM_Y));
|
||||
extern "C" void cuda_Copy(TColor *d_dst, int imageW, int imageH, cudaTextureObject_t texImage)
|
||||
{
|
||||
dim3 threads(BLOCKDIM_X, BLOCKDIM_Y);
|
||||
dim3 grid(iDivUp(imageW, BLOCKDIM_X), iDivUp(imageH, BLOCKDIM_Y));
|
||||
|
||||
Copy<<<grid, threads>>>(d_dst, imageW, imageH, texImage);
|
||||
Copy<<<grid, threads>>>(d_dst, imageW, imageH, texImage);
|
||||
}
|
||||
|
||||
@@ -28,119 +28,117 @@
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// KNN kernel
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
__global__ void KNN(TColor *dst, int imageW, int imageH, float Noise,
|
||||
float lerpC, cudaTextureObject_t texImage) {
|
||||
const int ix = blockDim.x * blockIdx.x + threadIdx.x;
|
||||
const int iy = blockDim.y * blockIdx.y + threadIdx.y;
|
||||
// Add half of a texel to always address exact texel centers
|
||||
const float x = (float)ix + 0.5f;
|
||||
const float y = (float)iy + 0.5f;
|
||||
__global__ void KNN(TColor *dst, int imageW, int imageH, float Noise, float lerpC, cudaTextureObject_t texImage)
|
||||
{
|
||||
const int ix = blockDim.x * blockIdx.x + threadIdx.x;
|
||||
const int iy = blockDim.y * blockIdx.y + threadIdx.y;
|
||||
// Add half of a texel to always address exact texel centers
|
||||
const float x = (float)ix + 0.5f;
|
||||
const float y = (float)iy + 0.5f;
|
||||
|
||||
if (ix < imageW && iy < imageH) {
|
||||
// Normalized counter for the weight threshold
|
||||
float fCount = 0;
|
||||
// Total sum of pixel weights
|
||||
float sumWeights = 0;
|
||||
// Result accumulator
|
||||
float3 clr = {0, 0, 0};
|
||||
// Center of the KNN window
|
||||
float4 clr00 = tex2D<float4>(texImage, x, y);
|
||||
if (ix < imageW && iy < imageH) {
|
||||
// Normalized counter for the weight threshold
|
||||
float fCount = 0;
|
||||
// Total sum of pixel weights
|
||||
float sumWeights = 0;
|
||||
// Result accumulator
|
||||
float3 clr = {0, 0, 0};
|
||||
// Center of the KNN window
|
||||
float4 clr00 = tex2D<float4>(texImage, x, y);
|
||||
|
||||
// Cycle through KNN window, surrounding (x, y) texel
|
||||
for (float i = -KNN_WINDOW_RADIUS; i <= KNN_WINDOW_RADIUS; i++)
|
||||
for (float j = -KNN_WINDOW_RADIUS; j <= KNN_WINDOW_RADIUS; j++) {
|
||||
float4 clrIJ = tex2D<float4>(texImage, x + j, y + i);
|
||||
float distanceIJ = vecLen(clr00, clrIJ);
|
||||
// Cycle through KNN window, surrounding (x, y) texel
|
||||
for (float i = -KNN_WINDOW_RADIUS; i <= KNN_WINDOW_RADIUS; i++)
|
||||
for (float j = -KNN_WINDOW_RADIUS; j <= KNN_WINDOW_RADIUS; j++) {
|
||||
float4 clrIJ = tex2D<float4>(texImage, x + j, y + i);
|
||||
float distanceIJ = vecLen(clr00, clrIJ);
|
||||
|
||||
// Derive final weight from color distance
|
||||
float weightIJ = __expf(
|
||||
-(distanceIJ * Noise + (i * i + j * j) * INV_KNN_WINDOW_AREA));
|
||||
// Derive final weight from color distance
|
||||
float weightIJ = __expf(-(distanceIJ * Noise + (i * i + j * j) * INV_KNN_WINDOW_AREA));
|
||||
|
||||
// Accumulate (x + j, y + i) texel color with computed weight
|
||||
clr.x += clrIJ.x * weightIJ;
|
||||
clr.y += clrIJ.y * weightIJ;
|
||||
clr.z += clrIJ.z * weightIJ;
|
||||
// Accumulate (x + j, y + i) texel color with computed weight
|
||||
clr.x += clrIJ.x * weightIJ;
|
||||
clr.y += clrIJ.y * weightIJ;
|
||||
clr.z += clrIJ.z * weightIJ;
|
||||
|
||||
// Sum of weights for color normalization to [0..1] range
|
||||
sumWeights += weightIJ;
|
||||
// Sum of weights for color normalization to [0..1] range
|
||||
sumWeights += weightIJ;
|
||||
|
||||
// Update weight counter, if KNN weight for current window texel
|
||||
// exceeds the weight threshold
|
||||
fCount += (weightIJ > KNN_WEIGHT_THRESHOLD) ? INV_KNN_WINDOW_AREA : 0;
|
||||
}
|
||||
// Update weight counter, if KNN weight for current window texel
|
||||
// exceeds the weight threshold
|
||||
fCount += (weightIJ > KNN_WEIGHT_THRESHOLD) ? INV_KNN_WINDOW_AREA : 0;
|
||||
}
|
||||
|
||||
// Normalize result color by sum of weights
|
||||
sumWeights = 1.0f / sumWeights;
|
||||
clr.x *= sumWeights;
|
||||
clr.y *= sumWeights;
|
||||
clr.z *= sumWeights;
|
||||
// Normalize result color by sum of weights
|
||||
sumWeights = 1.0f / sumWeights;
|
||||
clr.x *= sumWeights;
|
||||
clr.y *= sumWeights;
|
||||
clr.z *= sumWeights;
|
||||
|
||||
// Choose LERP quotient basing on how many texels
|
||||
// within the KNN window exceeded the weight threshold
|
||||
float lerpQ = (fCount > KNN_LERP_THRESHOLD) ? lerpC : 1.0f - lerpC;
|
||||
// Choose LERP quotient basing on how many texels
|
||||
// within the KNN window exceeded the weight threshold
|
||||
float lerpQ = (fCount > KNN_LERP_THRESHOLD) ? lerpC : 1.0f - lerpC;
|
||||
|
||||
// Write final result to global memory
|
||||
clr.x = lerpf(clr.x, clr00.x, lerpQ);
|
||||
clr.y = lerpf(clr.y, clr00.y, lerpQ);
|
||||
clr.z = lerpf(clr.z, clr00.z, lerpQ);
|
||||
dst[imageW * iy + ix] = make_color(clr.x, clr.y, clr.z, 0);
|
||||
};
|
||||
// Write final result to global memory
|
||||
clr.x = lerpf(clr.x, clr00.x, lerpQ);
|
||||
clr.y = lerpf(clr.y, clr00.y, lerpQ);
|
||||
clr.z = lerpf(clr.z, clr00.z, lerpQ);
|
||||
dst[imageW * iy + ix] = make_color(clr.x, clr.y, clr.z, 0);
|
||||
};
|
||||
}
|
||||
|
||||
extern "C" void cuda_KNN(TColor *d_dst, int imageW, int imageH, float Noise,
|
||||
float lerpC, cudaTextureObject_t texImage) {
|
||||
dim3 threads(BLOCKDIM_X, BLOCKDIM_Y);
|
||||
dim3 grid(iDivUp(imageW, BLOCKDIM_X), iDivUp(imageH, BLOCKDIM_Y));
|
||||
extern "C" void cuda_KNN(TColor *d_dst, int imageW, int imageH, float Noise, float lerpC, cudaTextureObject_t texImage)
|
||||
{
|
||||
dim3 threads(BLOCKDIM_X, BLOCKDIM_Y);
|
||||
dim3 grid(iDivUp(imageW, BLOCKDIM_X), iDivUp(imageH, BLOCKDIM_Y));
|
||||
|
||||
KNN<<<grid, threads>>>(d_dst, imageW, imageH, Noise, lerpC, texImage);
|
||||
KNN<<<grid, threads>>>(d_dst, imageW, imageH, Noise, lerpC, texImage);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Stripped KNN kernel, only highlighting areas with different LERP directions
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
__global__ void KNNdiag(TColor *dst, int imageW, int imageH, float Noise,
|
||||
float lerpC, cudaTextureObject_t texImage) {
|
||||
const int ix = blockDim.x * blockIdx.x + threadIdx.x;
|
||||
const int iy = blockDim.y * blockIdx.y + threadIdx.y;
|
||||
// Add half of a texel to always address exact texel centers
|
||||
const float x = (float)ix + 0.5f;
|
||||
const float y = (float)iy + 0.5f;
|
||||
__global__ void KNNdiag(TColor *dst, int imageW, int imageH, float Noise, float lerpC, cudaTextureObject_t texImage)
|
||||
{
|
||||
const int ix = blockDim.x * blockIdx.x + threadIdx.x;
|
||||
const int iy = blockDim.y * blockIdx.y + threadIdx.y;
|
||||
// Add half of a texel to always address exact texel centers
|
||||
const float x = (float)ix + 0.5f;
|
||||
const float y = (float)iy + 0.5f;
|
||||
|
||||
if (ix < imageW && iy < imageH) {
|
||||
// Normalized counter for the weight threshold
|
||||
float fCount = 0;
|
||||
// Center of the KNN window
|
||||
float4 clr00 = tex2D<float4>(texImage, x, y);
|
||||
if (ix < imageW && iy < imageH) {
|
||||
// Normalized counter for the weight threshold
|
||||
float fCount = 0;
|
||||
// Center of the KNN window
|
||||
float4 clr00 = tex2D<float4>(texImage, x, y);
|
||||
|
||||
// Cycle through KNN window, surrounding (x, y) texel
|
||||
for (float i = -KNN_WINDOW_RADIUS; i <= KNN_WINDOW_RADIUS; i++)
|
||||
for (float j = -KNN_WINDOW_RADIUS; j <= KNN_WINDOW_RADIUS; j++) {
|
||||
float4 clrIJ = tex2D<float4>(texImage, x + j, y + i);
|
||||
float distanceIJ = vecLen(clr00, clrIJ);
|
||||
// Cycle through KNN window, surrounding (x, y) texel
|
||||
for (float i = -KNN_WINDOW_RADIUS; i <= KNN_WINDOW_RADIUS; i++)
|
||||
for (float j = -KNN_WINDOW_RADIUS; j <= KNN_WINDOW_RADIUS; j++) {
|
||||
float4 clrIJ = tex2D<float4>(texImage, x + j, y + i);
|
||||
float distanceIJ = vecLen(clr00, clrIJ);
|
||||
|
||||
// Derive final weight from color and geometric distance
|
||||
float weightIJ = __expf(
|
||||
-(distanceIJ * Noise + (i * i + j * j) * INV_KNN_WINDOW_AREA));
|
||||
// Derive final weight from color and geometric distance
|
||||
float weightIJ = __expf(-(distanceIJ * Noise + (i * i + j * j) * INV_KNN_WINDOW_AREA));
|
||||
|
||||
// Update weight counter, if KNN weight for current window texel
|
||||
// exceeds the weight threshold
|
||||
fCount +=
|
||||
(weightIJ > KNN_WEIGHT_THRESHOLD) ? INV_KNN_WINDOW_AREA : 0.0f;
|
||||
}
|
||||
// Update weight counter, if KNN weight for current window texel
|
||||
// exceeds the weight threshold
|
||||
fCount += (weightIJ > KNN_WEIGHT_THRESHOLD) ? INV_KNN_WINDOW_AREA : 0.0f;
|
||||
}
|
||||
|
||||
// Choose LERP quotient basing on how many texels
|
||||
// within the KNN window exceeded the weight threshold
|
||||
float lerpQ = (fCount > KNN_LERP_THRESHOLD) ? 1.0f : 0;
|
||||
// Choose LERP quotient basing on how many texels
|
||||
// within the KNN window exceeded the weight threshold
|
||||
float lerpQ = (fCount > KNN_LERP_THRESHOLD) ? 1.0f : 0;
|
||||
|
||||
// Write final result to global memory
|
||||
dst[imageW * iy + ix] = make_color(lerpQ, 0, (1.0f - lerpQ), 0);
|
||||
};
|
||||
// Write final result to global memory
|
||||
dst[imageW * iy + ix] = make_color(lerpQ, 0, (1.0f - lerpQ), 0);
|
||||
};
|
||||
}
|
||||
|
||||
extern "C" void cuda_KNNdiag(TColor *d_dst, int imageW, int imageH, float Noise,
|
||||
float lerpC, cudaTextureObject_t texImage) {
|
||||
dim3 threads(BLOCKDIM_X, BLOCKDIM_Y);
|
||||
dim3 grid(iDivUp(imageW, BLOCKDIM_X), iDivUp(imageH, BLOCKDIM_Y));
|
||||
extern "C" void
|
||||
cuda_KNNdiag(TColor *d_dst, int imageW, int imageH, float Noise, float lerpC, cudaTextureObject_t texImage)
|
||||
{
|
||||
dim3 threads(BLOCKDIM_X, BLOCKDIM_Y);
|
||||
dim3 grid(iDivUp(imageW, BLOCKDIM_X), iDivUp(imageH, BLOCKDIM_Y));
|
||||
|
||||
KNNdiag<<<grid, threads>>>(d_dst, imageW, imageH, Noise, lerpC, texImage);
|
||||
KNNdiag<<<grid, threads>>>(d_dst, imageW, imageH, Noise, lerpC, texImage);
|
||||
}
|
||||
|
||||
@@ -48,170 +48,166 @@
|
||||
|
||||
namespace cg = cooperative_groups;
|
||||
|
||||
__global__ void NLM2(TColor *dst, int imageW, int imageH, float Noise,
|
||||
float lerpC, cudaTextureObject_t texImage) {
|
||||
// Handle to thread block group
|
||||
cg::thread_block cta = cg::this_thread_block();
|
||||
__global__ void NLM2(TColor *dst, int imageW, int imageH, float Noise, float lerpC, cudaTextureObject_t texImage)
|
||||
{
|
||||
// Handle to thread block group
|
||||
cg::thread_block cta = cg::this_thread_block();
|
||||
|
||||
// Weights cache
|
||||
__shared__ float fWeights[BLOCKDIM_X * BLOCKDIM_Y];
|
||||
// Weights cache
|
||||
__shared__ float fWeights[BLOCKDIM_X * BLOCKDIM_Y];
|
||||
|
||||
const int ix = blockDim.x * blockIdx.x + threadIdx.x;
|
||||
const int iy = blockDim.y * blockIdx.y + threadIdx.y;
|
||||
// Add half of a texel to always address exact texel centers
|
||||
const float x = (float)ix + 0.5f;
|
||||
const float y = (float)iy + 0.5f;
|
||||
const float cx = blockDim.x * blockIdx.x + NLM_WINDOW_RADIUS + 0.5f;
|
||||
const float cy = blockDim.x * blockIdx.y + NLM_WINDOW_RADIUS + 0.5f;
|
||||
const int ix = blockDim.x * blockIdx.x + threadIdx.x;
|
||||
const int iy = blockDim.y * blockIdx.y + threadIdx.y;
|
||||
// Add half of a texel to always address exact texel centers
|
||||
const float x = (float)ix + 0.5f;
|
||||
const float y = (float)iy + 0.5f;
|
||||
const float cx = blockDim.x * blockIdx.x + NLM_WINDOW_RADIUS + 0.5f;
|
||||
const float cy = blockDim.x * blockIdx.y + NLM_WINDOW_RADIUS + 0.5f;
|
||||
|
||||
if (ix < imageW && iy < imageH) {
|
||||
// Find color distance from current texel to the center of NLM window
|
||||
float weight = 0;
|
||||
if (ix < imageW && iy < imageH) {
|
||||
// Find color distance from current texel to the center of NLM window
|
||||
float weight = 0;
|
||||
|
||||
for (float n = -NLM_BLOCK_RADIUS; n <= NLM_BLOCK_RADIUS; n++)
|
||||
for (float m = -NLM_BLOCK_RADIUS; m <= NLM_BLOCK_RADIUS; m++)
|
||||
weight += vecLen(tex2D<float4>(texImage, cx + m, cy + n),
|
||||
tex2D<float4>(texImage, x + m, y + n));
|
||||
for (float n = -NLM_BLOCK_RADIUS; n <= NLM_BLOCK_RADIUS; n++)
|
||||
for (float m = -NLM_BLOCK_RADIUS; m <= NLM_BLOCK_RADIUS; m++)
|
||||
weight += vecLen(tex2D<float4>(texImage, cx + m, cy + n), tex2D<float4>(texImage, x + m, y + n));
|
||||
|
||||
// Geometric distance from current texel to the center of NLM window
|
||||
float dist =
|
||||
(threadIdx.x - NLM_WINDOW_RADIUS) * (threadIdx.x - NLM_WINDOW_RADIUS) +
|
||||
(threadIdx.y - NLM_WINDOW_RADIUS) * (threadIdx.y - NLM_WINDOW_RADIUS);
|
||||
// Geometric distance from current texel to the center of NLM window
|
||||
float dist = (threadIdx.x - NLM_WINDOW_RADIUS) * (threadIdx.x - NLM_WINDOW_RADIUS)
|
||||
+ (threadIdx.y - NLM_WINDOW_RADIUS) * (threadIdx.y - NLM_WINDOW_RADIUS);
|
||||
|
||||
// Derive final weight from color and geometric distance
|
||||
weight = __expf(-(weight * Noise + dist * INV_NLM_WINDOW_AREA));
|
||||
// Derive final weight from color and geometric distance
|
||||
weight = __expf(-(weight * Noise + dist * INV_NLM_WINDOW_AREA));
|
||||
|
||||
// Write the result to shared memory
|
||||
fWeights[threadIdx.y * BLOCKDIM_X + threadIdx.x] = weight;
|
||||
// Wait until all the weights are ready
|
||||
cg::sync(cta);
|
||||
// Write the result to shared memory
|
||||
fWeights[threadIdx.y * BLOCKDIM_X + threadIdx.x] = weight;
|
||||
// Wait until all the weights are ready
|
||||
cg::sync(cta);
|
||||
|
||||
// Normalized counter for the NLM weight threshold
|
||||
float fCount = 0;
|
||||
// Total sum of pixel weights
|
||||
float sumWeights = 0;
|
||||
// Result accumulator
|
||||
float3 clr = {0, 0, 0};
|
||||
// Normalized counter for the NLM weight threshold
|
||||
float fCount = 0;
|
||||
// Total sum of pixel weights
|
||||
float sumWeights = 0;
|
||||
// Result accumulator
|
||||
float3 clr = {0, 0, 0};
|
||||
|
||||
int idx = 0;
|
||||
int idx = 0;
|
||||
|
||||
// Cycle through NLM window, surrounding (x, y) texel
|
||||
for (float i = -NLM_WINDOW_RADIUS; i <= NLM_WINDOW_RADIUS + 1; i++)
|
||||
for (float j = -NLM_WINDOW_RADIUS; j <= NLM_WINDOW_RADIUS + 1; j++) {
|
||||
// Load precomputed weight
|
||||
float weightIJ = fWeights[idx++];
|
||||
// Cycle through NLM window, surrounding (x, y) texel
|
||||
for (float i = -NLM_WINDOW_RADIUS; i <= NLM_WINDOW_RADIUS + 1; i++)
|
||||
for (float j = -NLM_WINDOW_RADIUS; j <= NLM_WINDOW_RADIUS + 1; j++) {
|
||||
// Load precomputed weight
|
||||
float weightIJ = fWeights[idx++];
|
||||
|
||||
// Accumulate (x + j, y + i) texel color with computed weight
|
||||
float4 clrIJ = tex2D<float4>(texImage, x + j, y + i);
|
||||
clr.x += clrIJ.x * weightIJ;
|
||||
clr.y += clrIJ.y * weightIJ;
|
||||
clr.z += clrIJ.z * weightIJ;
|
||||
// Accumulate (x + j, y + i) texel color with computed weight
|
||||
float4 clrIJ = tex2D<float4>(texImage, x + j, y + i);
|
||||
clr.x += clrIJ.x * weightIJ;
|
||||
clr.y += clrIJ.y * weightIJ;
|
||||
clr.z += clrIJ.z * weightIJ;
|
||||
|
||||
// Sum of weights for color normalization to [0..1] range
|
||||
sumWeights += weightIJ;
|
||||
// Sum of weights for color normalization to [0..1] range
|
||||
sumWeights += weightIJ;
|
||||
|
||||
// Update weight counter, if NLM weight for current window texel
|
||||
// exceeds the weight threshold
|
||||
fCount += (weightIJ > NLM_WEIGHT_THRESHOLD) ? INV_NLM_WINDOW_AREA : 0;
|
||||
}
|
||||
// Update weight counter, if NLM weight for current window texel
|
||||
// exceeds the weight threshold
|
||||
fCount += (weightIJ > NLM_WEIGHT_THRESHOLD) ? INV_NLM_WINDOW_AREA : 0;
|
||||
}
|
||||
|
||||
// Normalize result color by sum of weights
|
||||
sumWeights = 1.0f / sumWeights;
|
||||
clr.x *= sumWeights;
|
||||
clr.y *= sumWeights;
|
||||
clr.z *= sumWeights;
|
||||
// Normalize result color by sum of weights
|
||||
sumWeights = 1.0f / sumWeights;
|
||||
clr.x *= sumWeights;
|
||||
clr.y *= sumWeights;
|
||||
clr.z *= sumWeights;
|
||||
|
||||
// Choose LERP quotient basing on how many texels
|
||||
// within the NLM window exceeded the weight threshold
|
||||
float lerpQ = (fCount > NLM_LERP_THRESHOLD) ? lerpC : 1.0f - lerpC;
|
||||
// Choose LERP quotient basing on how many texels
|
||||
// within the NLM window exceeded the weight threshold
|
||||
float lerpQ = (fCount > NLM_LERP_THRESHOLD) ? lerpC : 1.0f - lerpC;
|
||||
|
||||
// Write final result to global memory
|
||||
float4 clr00 = tex2D<float4>(texImage, x, y);
|
||||
clr.x = lerpf(clr.x, clr00.x, lerpQ);
|
||||
clr.y = lerpf(clr.y, clr00.y, lerpQ);
|
||||
clr.z = lerpf(clr.z, clr00.z, lerpQ);
|
||||
dst[imageW * iy + ix] = make_color(clr.x, clr.y, clr.z, 0);
|
||||
}
|
||||
// Write final result to global memory
|
||||
float4 clr00 = tex2D<float4>(texImage, x, y);
|
||||
clr.x = lerpf(clr.x, clr00.x, lerpQ);
|
||||
clr.y = lerpf(clr.y, clr00.y, lerpQ);
|
||||
clr.z = lerpf(clr.z, clr00.z, lerpQ);
|
||||
dst[imageW * iy + ix] = make_color(clr.x, clr.y, clr.z, 0);
|
||||
}
|
||||
}
|
||||
|
||||
extern "C" void cuda_NLM2(TColor *d_dst, int imageW, int imageH, float Noise,
|
||||
float LerpC, cudaTextureObject_t texImage) {
|
||||
dim3 threads(BLOCKDIM_X, BLOCKDIM_Y);
|
||||
dim3 grid(iDivUp(imageW, BLOCKDIM_X), iDivUp(imageH, BLOCKDIM_Y));
|
||||
extern "C" void cuda_NLM2(TColor *d_dst, int imageW, int imageH, float Noise, float LerpC, cudaTextureObject_t texImage)
|
||||
{
|
||||
dim3 threads(BLOCKDIM_X, BLOCKDIM_Y);
|
||||
dim3 grid(iDivUp(imageW, BLOCKDIM_X), iDivUp(imageH, BLOCKDIM_Y));
|
||||
|
||||
NLM2<<<grid, threads>>>(d_dst, imageW, imageH, Noise, LerpC, texImage);
|
||||
NLM2<<<grid, threads>>>(d_dst, imageW, imageH, Noise, LerpC, texImage);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Stripped NLM2 kernel, only highlighting areas with different LERP directions
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
__global__ void NLM2diag(TColor *dst, int imageW, int imageH, float Noise,
|
||||
float LerpC, cudaTextureObject_t texImage) {
|
||||
// Handle to thread block group
|
||||
cg::thread_block cta = cg::this_thread_block();
|
||||
__global__ void NLM2diag(TColor *dst, int imageW, int imageH, float Noise, float LerpC, cudaTextureObject_t texImage)
|
||||
{
|
||||
// Handle to thread block group
|
||||
cg::thread_block cta = cg::this_thread_block();
|
||||
|
||||
// Weights cache
|
||||
__shared__ float fWeights[BLOCKDIM_X * BLOCKDIM_Y];
|
||||
// Weights cache
|
||||
__shared__ float fWeights[BLOCKDIM_X * BLOCKDIM_Y];
|
||||
|
||||
const int ix = blockDim.x * blockIdx.x + threadIdx.x;
|
||||
const int iy = blockDim.y * blockIdx.y + threadIdx.y;
|
||||
// Add half of a texel to always address exact texel centers
|
||||
const float x = (float)ix + 0.5f;
|
||||
const float y = (float)iy + 0.5f;
|
||||
const float cx = blockDim.x * blockIdx.x + NLM_WINDOW_RADIUS + 0.5f;
|
||||
const float cy = blockDim.x * blockIdx.y + NLM_WINDOW_RADIUS + 0.5f;
|
||||
const int ix = blockDim.x * blockIdx.x + threadIdx.x;
|
||||
const int iy = blockDim.y * blockIdx.y + threadIdx.y;
|
||||
// Add half of a texel to always address exact texel centers
|
||||
const float x = (float)ix + 0.5f;
|
||||
const float y = (float)iy + 0.5f;
|
||||
const float cx = blockDim.x * blockIdx.x + NLM_WINDOW_RADIUS + 0.5f;
|
||||
const float cy = blockDim.x * blockIdx.y + NLM_WINDOW_RADIUS + 0.5f;
|
||||
|
||||
if (ix < imageW && iy < imageH) {
|
||||
// Find color distance from current texel to the center of NLM window
|
||||
float weight = 0;
|
||||
if (ix < imageW && iy < imageH) {
|
||||
// Find color distance from current texel to the center of NLM window
|
||||
float weight = 0;
|
||||
|
||||
for (float n = -NLM_BLOCK_RADIUS; n <= NLM_BLOCK_RADIUS + 1; n++)
|
||||
for (float m = -NLM_BLOCK_RADIUS; m <= NLM_BLOCK_RADIUS + 1; m++)
|
||||
weight += vecLen(tex2D<float4>(texImage, cx + m, cy + n),
|
||||
tex2D<float4>(texImage, x + m, y + n));
|
||||
for (float n = -NLM_BLOCK_RADIUS; n <= NLM_BLOCK_RADIUS + 1; n++)
|
||||
for (float m = -NLM_BLOCK_RADIUS; m <= NLM_BLOCK_RADIUS + 1; m++)
|
||||
weight += vecLen(tex2D<float4>(texImage, cx + m, cy + n), tex2D<float4>(texImage, x + m, y + n));
|
||||
|
||||
// Geometric distance from current texel to the center of NLM window
|
||||
float dist =
|
||||
(threadIdx.x - NLM_WINDOW_RADIUS) * (threadIdx.x - NLM_WINDOW_RADIUS) +
|
||||
(threadIdx.y - NLM_WINDOW_RADIUS) * (threadIdx.y - NLM_WINDOW_RADIUS);
|
||||
// Geometric distance from current texel to the center of NLM window
|
||||
float dist = (threadIdx.x - NLM_WINDOW_RADIUS) * (threadIdx.x - NLM_WINDOW_RADIUS)
|
||||
+ (threadIdx.y - NLM_WINDOW_RADIUS) * (threadIdx.y - NLM_WINDOW_RADIUS);
|
||||
|
||||
// Derive final weight from color and geometric distance
|
||||
weight = __expf(-(weight * Noise + dist * INV_NLM_WINDOW_AREA));
|
||||
// Derive final weight from color and geometric distance
|
||||
weight = __expf(-(weight * Noise + dist * INV_NLM_WINDOW_AREA));
|
||||
|
||||
// Write the result to shared memory
|
||||
fWeights[threadIdx.y * BLOCKDIM_X + threadIdx.x] = weight;
|
||||
// Wait until all the weights are ready
|
||||
cg::sync(cta);
|
||||
// Write the result to shared memory
|
||||
fWeights[threadIdx.y * BLOCKDIM_X + threadIdx.x] = weight;
|
||||
// Wait until all the weights are ready
|
||||
cg::sync(cta);
|
||||
|
||||
// Normalized counter for the NLM weight threshold
|
||||
float fCount = 0;
|
||||
int idx = 0;
|
||||
// Normalized counter for the NLM weight threshold
|
||||
float fCount = 0;
|
||||
int idx = 0;
|
||||
|
||||
// Cycle through NLM window, surrounding (x, y) texel
|
||||
for (float n = -NLM_WINDOW_RADIUS; n <= NLM_WINDOW_RADIUS + 1; n++)
|
||||
for (float m = -NLM_WINDOW_RADIUS; m <= NLM_WINDOW_RADIUS + 1; m++) {
|
||||
// Load precomputed weight
|
||||
float weightIJ = fWeights[idx++];
|
||||
// Cycle through NLM window, surrounding (x, y) texel
|
||||
for (float n = -NLM_WINDOW_RADIUS; n <= NLM_WINDOW_RADIUS + 1; n++)
|
||||
for (float m = -NLM_WINDOW_RADIUS; m <= NLM_WINDOW_RADIUS + 1; m++) {
|
||||
// Load precomputed weight
|
||||
float weightIJ = fWeights[idx++];
|
||||
|
||||
// Update weight counter, if NLM weight for current window texel
|
||||
// exceeds the weight threshold
|
||||
fCount += (weightIJ > NLM_WEIGHT_THRESHOLD) ? INV_NLM_WINDOW_AREA : 0;
|
||||
}
|
||||
// Update weight counter, if NLM weight for current window texel
|
||||
// exceeds the weight threshold
|
||||
fCount += (weightIJ > NLM_WEIGHT_THRESHOLD) ? INV_NLM_WINDOW_AREA : 0;
|
||||
}
|
||||
|
||||
// Choose LERP quotient basing on how many texels
|
||||
// within the NLM window exceeded the weight threshold
|
||||
float lerpQ = (fCount > NLM_LERP_THRESHOLD) ? 1.0f : 0.0f;
|
||||
// Choose LERP quotient basing on how many texels
|
||||
// within the NLM window exceeded the weight threshold
|
||||
float lerpQ = (fCount > NLM_LERP_THRESHOLD) ? 1.0f : 0.0f;
|
||||
|
||||
// Write final result to global memory
|
||||
dst[imageW * iy + ix] = make_color(lerpQ, 0, (1.0f - lerpQ), 0);
|
||||
};
|
||||
// Write final result to global memory
|
||||
dst[imageW * iy + ix] = make_color(lerpQ, 0, (1.0f - lerpQ), 0);
|
||||
};
|
||||
}
|
||||
|
||||
extern "C" void cuda_NLM2diag(TColor *d_dst, int imageW, int imageH,
|
||||
float Noise, float LerpC,
|
||||
cudaTextureObject_t texImage) {
|
||||
dim3 threads(BLOCKDIM_X, BLOCKDIM_Y);
|
||||
dim3 grid(iDivUp(imageW, BLOCKDIM_X), iDivUp(imageH, BLOCKDIM_Y));
|
||||
extern "C" void
|
||||
cuda_NLM2diag(TColor *d_dst, int imageW, int imageH, float Noise, float LerpC, cudaTextureObject_t texImage)
|
||||
{
|
||||
dim3 threads(BLOCKDIM_X, BLOCKDIM_Y);
|
||||
dim3 grid(iDivUp(imageW, BLOCKDIM_X), iDivUp(imageH, BLOCKDIM_Y));
|
||||
|
||||
NLM2diag<<<grid, threads>>>(d_dst, imageW, imageH, Noise, LerpC, texImage);
|
||||
NLM2diag<<<grid, threads>>>(d_dst, imageW, imageH, Noise, LerpC, texImage);
|
||||
}
|
||||
|
||||
@@ -28,126 +28,125 @@
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// NLM kernel
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
__global__ void NLM(TColor *dst, int imageW, int imageH, float Noise,
|
||||
float lerpC, cudaTextureObject_t texImage) {
|
||||
const int ix = blockDim.x * blockIdx.x + threadIdx.x;
|
||||
const int iy = blockDim.y * blockIdx.y + threadIdx.y;
|
||||
// Add half of a texel to always address exact texel centers
|
||||
const float x = (float)ix + 0.5f;
|
||||
const float y = (float)iy + 0.5f;
|
||||
__global__ void NLM(TColor *dst, int imageW, int imageH, float Noise, float lerpC, cudaTextureObject_t texImage)
|
||||
{
|
||||
const int ix = blockDim.x * blockIdx.x + threadIdx.x;
|
||||
const int iy = blockDim.y * blockIdx.y + threadIdx.y;
|
||||
// Add half of a texel to always address exact texel centers
|
||||
const float x = (float)ix + 0.5f;
|
||||
const float y = (float)iy + 0.5f;
|
||||
|
||||
if (ix < imageW && iy < imageH) {
|
||||
// Normalized counter for the NLM weight threshold
|
||||
float fCount = 0;
|
||||
// Total sum of pixel weights
|
||||
float sumWeights = 0;
|
||||
// Result accumulator
|
||||
float3 clr = {0, 0, 0};
|
||||
if (ix < imageW && iy < imageH) {
|
||||
// Normalized counter for the NLM weight threshold
|
||||
float fCount = 0;
|
||||
// Total sum of pixel weights
|
||||
float sumWeights = 0;
|
||||
// Result accumulator
|
||||
float3 clr = {0, 0, 0};
|
||||
|
||||
// Cycle through NLM window, surrounding (x, y) texel
|
||||
for (float i = -NLM_WINDOW_RADIUS; i <= NLM_WINDOW_RADIUS; i++)
|
||||
for (float j = -NLM_WINDOW_RADIUS; j <= NLM_WINDOW_RADIUS; j++) {
|
||||
// Find color distance from (x, y) to (x + j, y + i)
|
||||
float weightIJ = 0;
|
||||
// Cycle through NLM window, surrounding (x, y) texel
|
||||
for (float i = -NLM_WINDOW_RADIUS; i <= NLM_WINDOW_RADIUS; i++)
|
||||
for (float j = -NLM_WINDOW_RADIUS; j <= NLM_WINDOW_RADIUS; j++) {
|
||||
// Find color distance from (x, y) to (x + j, y + i)
|
||||
float weightIJ = 0;
|
||||
|
||||
for (float n = -NLM_BLOCK_RADIUS; n <= NLM_BLOCK_RADIUS; n++)
|
||||
for (float m = -NLM_BLOCK_RADIUS; m <= NLM_BLOCK_RADIUS; m++)
|
||||
weightIJ += vecLen(tex2D<float4>(texImage, x + j + m, y + i + n),
|
||||
tex2D<float4>(texImage, x + m, y + n));
|
||||
for (float n = -NLM_BLOCK_RADIUS; n <= NLM_BLOCK_RADIUS; n++)
|
||||
for (float m = -NLM_BLOCK_RADIUS; m <= NLM_BLOCK_RADIUS; m++)
|
||||
weightIJ += vecLen(tex2D<float4>(texImage, x + j + m, y + i + n),
|
||||
tex2D<float4>(texImage, x + m, y + n));
|
||||
|
||||
// Derive final weight from color and geometric distance
|
||||
weightIJ =
|
||||
__expf(-(weightIJ * Noise + (i * i + j * j) * INV_NLM_WINDOW_AREA));
|
||||
// Derive final weight from color and geometric distance
|
||||
weightIJ = __expf(-(weightIJ * Noise + (i * i + j * j) * INV_NLM_WINDOW_AREA));
|
||||
|
||||
// Accumulate (x + j, y + i) texel color with computed weight
|
||||
float4 clrIJ = tex2D<float4>(texImage, x + j, y + i);
|
||||
clr.x += clrIJ.x * weightIJ;
|
||||
clr.y += clrIJ.y * weightIJ;
|
||||
clr.z += clrIJ.z * weightIJ;
|
||||
// Accumulate (x + j, y + i) texel color with computed weight
|
||||
float4 clrIJ = tex2D<float4>(texImage, x + j, y + i);
|
||||
clr.x += clrIJ.x * weightIJ;
|
||||
clr.y += clrIJ.y * weightIJ;
|
||||
clr.z += clrIJ.z * weightIJ;
|
||||
|
||||
// Sum of weights for color normalization to [0..1] range
|
||||
sumWeights += weightIJ;
|
||||
// Sum of weights for color normalization to [0..1] range
|
||||
sumWeights += weightIJ;
|
||||
|
||||
// Update weight counter, if NLM weight for current window texel
|
||||
// exceeds the weight threshold
|
||||
fCount += (weightIJ > NLM_WEIGHT_THRESHOLD) ? INV_NLM_WINDOW_AREA : 0;
|
||||
}
|
||||
// Update weight counter, if NLM weight for current window texel
|
||||
// exceeds the weight threshold
|
||||
fCount += (weightIJ > NLM_WEIGHT_THRESHOLD) ? INV_NLM_WINDOW_AREA : 0;
|
||||
}
|
||||
|
||||
// Normalize result color by sum of weights
|
||||
sumWeights = 1.0f / sumWeights;
|
||||
clr.x *= sumWeights;
|
||||
clr.y *= sumWeights;
|
||||
clr.z *= sumWeights;
|
||||
// Normalize result color by sum of weights
|
||||
sumWeights = 1.0f / sumWeights;
|
||||
clr.x *= sumWeights;
|
||||
clr.y *= sumWeights;
|
||||
clr.z *= sumWeights;
|
||||
|
||||
// Choose LERP quotient basing on how many texels
|
||||
// within the NLM window exceeded the weight threshold
|
||||
float lerpQ = (fCount > NLM_LERP_THRESHOLD) ? lerpC : 1.0f - lerpC;
|
||||
// Choose LERP quotient basing on how many texels
|
||||
// within the NLM window exceeded the weight threshold
|
||||
float lerpQ = (fCount > NLM_LERP_THRESHOLD) ? lerpC : 1.0f - lerpC;
|
||||
|
||||
// Write final result to global memory
|
||||
float4 clr00 = tex2D<float4>(texImage, x, y);
|
||||
clr.x = lerpf(clr.x, clr00.x, lerpQ);
|
||||
clr.y = lerpf(clr.y, clr00.y, lerpQ);
|
||||
clr.z = lerpf(clr.z, clr00.z, lerpQ);
|
||||
dst[imageW * iy + ix] = make_color(clr.x, clr.y, clr.z, 0);
|
||||
}
|
||||
// Write final result to global memory
|
||||
float4 clr00 = tex2D<float4>(texImage, x, y);
|
||||
clr.x = lerpf(clr.x, clr00.x, lerpQ);
|
||||
clr.y = lerpf(clr.y, clr00.y, lerpQ);
|
||||
clr.z = lerpf(clr.z, clr00.z, lerpQ);
|
||||
dst[imageW * iy + ix] = make_color(clr.x, clr.y, clr.z, 0);
|
||||
}
|
||||
}
|
||||
|
||||
extern "C" void cuda_NLM(TColor *d_dst, int imageW, int imageH, float Noise,
|
||||
float lerpC, cudaTextureObject_t texImage) {
|
||||
dim3 threads(BLOCKDIM_X, BLOCKDIM_Y);
|
||||
dim3 grid(iDivUp(imageW, BLOCKDIM_X), iDivUp(imageH, BLOCKDIM_Y));
|
||||
extern "C" void cuda_NLM(TColor *d_dst, int imageW, int imageH, float Noise, float lerpC, cudaTextureObject_t texImage)
|
||||
{
|
||||
dim3 threads(BLOCKDIM_X, BLOCKDIM_Y);
|
||||
dim3 grid(iDivUp(imageW, BLOCKDIM_X), iDivUp(imageH, BLOCKDIM_Y));
|
||||
|
||||
NLM<<<grid, threads>>>(d_dst, imageW, imageH, Noise, lerpC, texImage);
|
||||
NLM<<<grid, threads>>>(d_dst, imageW, imageH, Noise, lerpC, texImage);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Stripped NLM kernel, only highlighting areas with different LERP directions
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
__global__ void NLMdiag(TColor *dst, unsigned int imageW, unsigned int imageH,
|
||||
float Noise, float lerpC,
|
||||
cudaTextureObject_t texImage) {
|
||||
const int ix = blockDim.x * blockIdx.x + threadIdx.x;
|
||||
const int iy = blockDim.y * blockIdx.y + threadIdx.y;
|
||||
// Add half of a texel to always address exact texel centers
|
||||
const float x = (float)ix + 0.5f;
|
||||
const float y = (float)iy + 0.5f;
|
||||
__global__ void
|
||||
NLMdiag(TColor *dst, unsigned int imageW, unsigned int imageH, float Noise, float lerpC, cudaTextureObject_t texImage)
|
||||
{
|
||||
const int ix = blockDim.x * blockIdx.x + threadIdx.x;
|
||||
const int iy = blockDim.y * blockIdx.y + threadIdx.y;
|
||||
// Add half of a texel to always address exact texel centers
|
||||
const float x = (float)ix + 0.5f;
|
||||
const float y = (float)iy + 0.5f;
|
||||
|
||||
if (ix < imageW && iy < imageH) {
|
||||
// Normalized counter for the weight threshold
|
||||
float fCount = 0;
|
||||
if (ix < imageW && iy < imageH) {
|
||||
// Normalized counter for the weight threshold
|
||||
float fCount = 0;
|
||||
|
||||
// Cycle through NLM window, surrounding (x, y) texel
|
||||
for (float i = -NLM_WINDOW_RADIUS; i <= NLM_WINDOW_RADIUS; i++)
|
||||
for (float j = -NLM_WINDOW_RADIUS; j <= NLM_WINDOW_RADIUS; j++) {
|
||||
// Find color distance between (x, y) and (x + j, y + i)
|
||||
float weightIJ = 0;
|
||||
// Cycle through NLM window, surrounding (x, y) texel
|
||||
for (float i = -NLM_WINDOW_RADIUS; i <= NLM_WINDOW_RADIUS; i++)
|
||||
for (float j = -NLM_WINDOW_RADIUS; j <= NLM_WINDOW_RADIUS; j++) {
|
||||
// Find color distance between (x, y) and (x + j, y + i)
|
||||
float weightIJ = 0;
|
||||
|
||||
for (float n = -NLM_BLOCK_RADIUS; n <= NLM_BLOCK_RADIUS; n++)
|
||||
for (float m = -NLM_BLOCK_RADIUS; m <= NLM_BLOCK_RADIUS; m++)
|
||||
weightIJ += vecLen(tex2D<float4>(texImage, x + j + m, y + i + n),
|
||||
tex2D<float4>(texImage, x + m, y + n));
|
||||
for (float n = -NLM_BLOCK_RADIUS; n <= NLM_BLOCK_RADIUS; n++)
|
||||
for (float m = -NLM_BLOCK_RADIUS; m <= NLM_BLOCK_RADIUS; m++)
|
||||
weightIJ += vecLen(tex2D<float4>(texImage, x + j + m, y + i + n),
|
||||
tex2D<float4>(texImage, x + m, y + n));
|
||||
|
||||
// Derive final weight from color and geometric distance
|
||||
weightIJ =
|
||||
__expf(-(weightIJ * Noise + (i * i + j * j) * INV_NLM_WINDOW_AREA));
|
||||
// Derive final weight from color and geometric distance
|
||||
weightIJ = __expf(-(weightIJ * Noise + (i * i + j * j) * INV_NLM_WINDOW_AREA));
|
||||
|
||||
// Increase the weight threshold counter
|
||||
fCount += (weightIJ > NLM_WEIGHT_THRESHOLD) ? INV_NLM_WINDOW_AREA : 0;
|
||||
}
|
||||
// Increase the weight threshold counter
|
||||
fCount += (weightIJ > NLM_WEIGHT_THRESHOLD) ? INV_NLM_WINDOW_AREA : 0;
|
||||
}
|
||||
|
||||
// Choose LERP quotient basing on how many texels
|
||||
// within the NLM window exceeded the LERP threshold
|
||||
float lerpQ = (fCount > NLM_LERP_THRESHOLD) ? 1.0f : 0;
|
||||
// Choose LERP quotient basing on how many texels
|
||||
// within the NLM window exceeded the LERP threshold
|
||||
float lerpQ = (fCount > NLM_LERP_THRESHOLD) ? 1.0f : 0;
|
||||
|
||||
// Write final result to global memory
|
||||
dst[imageW * iy + ix] = make_color(lerpQ, 0, (1.0f - lerpQ), 0);
|
||||
};
|
||||
// Write final result to global memory
|
||||
dst[imageW * iy + ix] = make_color(lerpQ, 0, (1.0f - lerpQ), 0);
|
||||
};
|
||||
}
|
||||
|
||||
extern "C" void cuda_NLMdiag(TColor *d_dst, int imageW, int imageH, float Noise,
|
||||
float lerpC, cudaTextureObject_t texImage) {
|
||||
dim3 threads(BLOCKDIM_X, BLOCKDIM_Y);
|
||||
dim3 grid(iDivUp(imageW, BLOCKDIM_X), iDivUp(imageH, BLOCKDIM_Y));
|
||||
extern "C" void
|
||||
cuda_NLMdiag(TColor *d_dst, int imageW, int imageH, float Noise, float lerpC, cudaTextureObject_t texImage)
|
||||
{
|
||||
dim3 threads(BLOCKDIM_X, BLOCKDIM_Y);
|
||||
dim3 grid(iDivUp(imageW, BLOCKDIM_X), iDivUp(imageH, BLOCKDIM_Y));
|
||||
|
||||
NLMdiag<<<grid, threads>>>(d_dst, imageW, imageH, Noise, lerpC, texImage);
|
||||
NLMdiag<<<grid, threads>>>(d_dst, imageW, imageH, Noise, lerpC, texImage);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user