問題
c言語とopenmpでCPUで並列に画像を90度回転させるプログラムを作った際に、実行結果の画像(下に記載)にゴマ塩ノイズが含まれてしまいます。コンパイル時に特にエラーは出ず、画像をピクセルの配列として受け取って、各要素の位置を入れかえているだけなので、計算のプログラムが間違えていて要素の値が0~255の範囲外になってしまっていることはないと思います。また、同様の計算をopenmpなしの処理、コンパイルオプションで-openmpを入れないとき(画像は省略)、cudaによるGPU並列で行った結果にはノイズは含まれません。
ここからは私の推測なのですが、CPUが故障しているのではないかと思っています。普段使いしている分には何もバグのようなことはないですが、Apexをしていると音飛びやゲーム画面が閉じてしまうことがあります。(PCのスペックは足りていると思います。)
上記の問題を調べてもわからなかったので何か少しでも原因に心当たりのある方、助けていただきたいです。よろしくお願いします。
環境
OS:windows11 Home
CPU:AMD Ryzen 5 5600X 6-Core Processor 3.70 GHz
GPU:NVIDIA GeForce RTX 3060Ti
RAM:16GB
ソースコード
C言語(openmpなし)
1#include <stdio.h> 2#include <stdlib.h> 3#include <string.h> 4#include <omp.h> 5 6#define Nx 1024 7#define Ny 1024 8 9int main() 10{ 11 int i, j, ID, ID_in, ID_out; 12 double start, end; /* 時間計測用 */ 13 14 float* h_IMG_input; /* 入力データ用 */ 15 float* h_IMG_output; /* 出力データ用 */ 16 17 h_IMG_input = (float*)malloc(sizeof(float) * Nx * Ny); /* 入力データ用 */ 18 h_IMG_output = (float*)malloc(sizeof(float) * Nx * Ny); /* 出力データ用 */ 19 20 memset(h_IMG_input, 0, sizeof(float) * Nx * Ny); /* 入力データ用 */ 21 memset(h_IMG_output, 0, sizeof(float) * Nx * Ny); /* 出力データ用 */ 22 23 //ファイルよりデータ入力 24 FILE* fp; /* 入出ファイル用 */ 25 fp = fopen("./lenna1024.img", "r"); /* 読込みモードでファイルをオープンする */ 26 if (fp == NULL) { 27 printf("ファイルを開くことが出来ませんでした.\n"); 28 return; 29 } 30 31 for (j = 0; j < Ny; j++) { 32 for (i = 0; i < Nx; i++) { 33 ID = i + j * Nx; 34 fscanf(fp, "%f", &(h_IMG_input[ID])); /* 1行読む → h_IMG_input[ID])に入れる */ 35 } 36 } 37 38 fclose(fp); /* ファイルをクローズする */ 39 40 //時間計測開始 41 start = omp_get_wtime(); 42 43 // 画像を90度右回りに回転させる 44 for (j = 0; j < Ny; j++) { 45 for (i = 0; i < Nx; i++) { 46 ID_in = i + j * Nx; 47 ID_out = j + (1023 - i) * Nx; 48 h_IMG_output[ID_out] = h_IMG_input[ID_in]; 49 } 50 } 51 52 //時間計測終了 53 end = omp_get_wtime(); 54 printf("\nCalculation End\n"); 55 printf("\n Processing Time : %.3f [msec]\n", 1e3 * (end - start)); 56 57 58 //出力用データをファイルに書き込む 59 fp = fopen("a_c.img", "w"); /* 書込みモードでファイルをオープンする */ 60 61 if (fp == NULL) { 62 printf("ファイルを作れませんでした"); 63 return; /* ここでプログラム終了 */ 64 } 65 66 for (j = 0; j < Ny; j++) { 67 for (i = 0; i < Nx; i++) { 68 ID = i + j * Nx; 69 fprintf(fp, "%d\n", (unsigned char)h_IMG_output[ID]); /* 1行書込み → h_IMG_output[ID])に入れる */ 70 } 71 } 72 73 fclose(fp); 74 75 76 //メモリ解放 77 free(h_IMG_input); 78 free(h_IMG_output); 79 80 return 0; 81} 82
実行結果の画像
C言語(Openmp)
1上記のコードと画像処理の部分以外は同じ 2// 画像を90度右回りに回転させる 3 #pragma omp parallel for private(i) 4 for (j = 0; j < Ny; j++) { 5 for (i = 0; i < Nx; i++) { 6 ID_in = i + j * Nx; 7 ID_out = j + (1023 - i) * Nx; 8 h_IMG_output[ID_out] = h_IMG_input[ID_in]; 9 } 10 }
実行結果の画像
C(cuda)
1#include <stdio.h> 2#include <stdlib.h> 3#include <string.h> 4 5#include <cuda.h> 6#include <cuda_runtime.h> 7#include <cuda_runtime_api.h> 8 9#define HTH cudaMemcpyHostToHost 10#define HTD cudaMemcpyHostToDevice 11#define DTH cudaMemcpyDeviceToHost 12#define DTD cudaMemcpyDeviceToDevice 13 14#define Nx 1024 15#define Ny 1024 16 17#define Db_x 16 18#define Db_y 16 19#define Db_z 1 20 21#define Dg_x (Nx / Db_x) 22#define Dg_y (Ny / Db_y) 23#define Dg_z 1 24 25dim3 Db(Db_x, Db_y, Db_z); 26dim3 Dg(Dg_x, Dg_y, Dg_z); 27 28float* h_IMG_input; /* 入力データ用(Host) */ 29float* h_IMG_output; /* 出力データ用(Host) */ 30 31float* d_IMG_input; /* 入力データ用(Device) */ 32float* d_IMG_output; /* 出力データ用(Device) */ 33 34cudaEvent_t start, end; /* 時間計測用 */ 35float timer; /* 時間計測用 */ 36 37int element = sizeof(float) * Nx * Ny; 38 39// 画像を右に90度回転させる 40__global__ void rotate(float* d_IMG_input, float* d_IMG_output) 41{ 42 int X, Y, ID_in, ID_out; 43 44 X = threadIdx.x + (blockIdx.x * blockDim.x); 45 Y = threadIdx.y + (blockIdx.y * blockDim.y); 46 47 ID_in = X + Y * Nx; 48 ID_out = Y + (1023 - X) * Nx; 49 d_IMG_output[ID_out] = d_IMG_input[ID_in]; 50} 51 52int main() 53{ 54 int GPU_Num = 0; 55 56 cudaSetDevice(GPU_Num); 57 58 printf("convert_color.cu\n"); 59 printf("Nx = %d, Ny = %d\n", Nx, Ny); 60 printf("Number %d GPU working\n", GPU_Num); 61 62 int i, j, ID; 63 64 // デバイス(VRAM内)に要素を確保 65 cudaMalloc((void**)&d_IMG_input, element); 66 cudaMalloc((void**)&d_IMG_output, element); 67 68 cudaMemset(d_IMG_input, 0, element); 69 cudaMemset(d_IMG_output, 0, element); 70 71 // ホスト(RAM内)に要素を確保 72 cudaHostAlloc((void**)&h_IMG_input, element, cudaHostAllocPortable); 73 cudaHostAlloc((void**)&h_IMG_output, element, cudaHostAllocPortable); 74 75 memset(h_IMG_input, 0, element); 76 memset(h_IMG_output, 0, element); 77 78 //ファイルよりデータ入力 79 FILE* fp; /* 入出ファイル用 */ 80 81 fp = fopen("./lenna1024.img", "r"); /* 読込みモードでファイルをオープンする */ 82 if (fp == NULL) { 83 printf("ファイルを開くことが出来ませんでした.\n"); 84 return 0; 85 } 86 87 for (j = 0; j < Ny; j++) { 88 for (i = 0; i < Nx; i++) { 89 ID = i + j * Nx; 90 fscanf(fp, "%f", &(h_IMG_input[ID])); /* 1行読む → h_IMG_input[ID])に入れる */ 91 } 92 } 93 94 fclose(fp); /* ファイルをクローズする */ 95 96 97 // 演算時間を計測するためのcudaEventCreateを実行 98 cudaEventCreate(&start); 99 cudaEventCreate(&end); 100 101 printf("\nCalculation Start\n"); 102 103 cudaMemcpy(d_IMG_input, h_IMG_input, element, HTD); 104 105 // 演算時間を計測するためのcudaEventRecordを実行し計算の開始を記録 106 cudaEventRecord(start, 0); 107 108 109 // 画像を右に90度回転させる 110 rotate<<< Dg, Db >>>(d_IMG_input, d_IMG_output); 111 cudaThreadSynchronize(); 112 113 // 演算時間を計測するためのcudaEventRecordを実行し計算の終了を記録 114 cudaEventRecord(end, 0); 115 116 // 演算時間を算出 117 cudaEventSynchronize(end); 118 cudaEventElapsedTime(&timer, start, end); 119 120 printf("\nCalculation End\n"); 121 122 printf("\nProcessing Time : %.3f [msec]\n", timer); 123 124 /* File Output */ 125 cudaMemcpy(h_IMG_output, d_IMG_output, element, DTH); 126 127 //出力用データをファイルに書き込む 128 fp = fopen("a_cuda.img", "w"); /* 書込みモードでファイルをオープンする */ 129 130 if (fp == NULL) { 131 printf("ファイルを作れませんでした"); 132 return 0; /* ここでプログラム終了 */ 133 } 134 135 for (j = 0; j < Ny; j++) { 136 for (i = 0; i < Nx; i++) { 137 ID = i + j * Nx; 138 fprintf(fp, "%d\n", (unsigned char)h_IMG_output[ID]); /* 1行書込み → h_IMG_output[ID])に入れる */ 139 } 140 } 141 142 fclose(fp); 143 144 cudaFree(d_IMG_input); 145 cudaFree(d_IMG_output); 146 147 cudaFreeHost(h_IMG_input); 148 cudaFreeHost(h_IMG_output); 149 150 cudaEventDestroy(start); 151 cudaEventDestroy(end); 152 153 return 0; 154} 155
実行結果の画像
回答1件
あなたの回答
tips
プレビュー