2016-04-13 13 views
0

私はCUDAを初めて使用しています。私はCUDAを初めて使用しようとしています。私は、GPUに画像データをプッシュしようとしています、それを白黒にして、それを新しい画像に書き込みます。しかし、プログラムは私に黒と白のバージョンの代わりに黒のイメージを与えます。私は間違って何をしていますか?画像の幅と高さは3840x2160です。 Source imageCUDAでの画像処理に関するトラブル

Output image

__global__ void addMatrix(unsigned char *DataOut, unsigned char *DataIn) 
{ 
    int idx = threadIdx.x; 
    DataOut[idx] = (DataIn[idx] + DataIn[idx + 1] + DataIn[idx + 2])/3; 
    // 
} 
int main() 

{ 

int iWidth, iHeight, iBpp, iHeightOut, iWidthOut; 

vector<unsigned char> pDataIn; 
vector<unsigned char> pDataOut; 


int error1 = LoadBmpFile(L"3840x2160.bmp", iWidth, iHeight, iBpp, pDataIn); 

if (error1 != 0 || pDataIn.size() == 0 || iBpp != 32) 
{ 
    std::cout << "erroror load input file!\n"; 
} 


pDataOut.resize(pDataIn.size()/4); 

unsigned int SizeIn, SizeOut; 
unsigned char *devDatOut, *devDatIn, *PInData, *POutData; 

int i = 0; 
SizeIn = pDataIn.size(); 
SizeOut = pDataOut.size(); 
PInData = pDataIn.data(); 
POutData = pDataOut.data(); 

i = cudaMalloc((void**)&devDatIn, SizeIn * sizeof(unsigned char)); 
if(i != 0) 
{ 
printf("cudaMalloc __e FAIL! Code: %d\n", i); 
_getch(); 
} 
i = cudaMalloc((void**)&devDatOut, SizeOut * sizeof(unsigned char)); 
if(i != cudaSuccess) 
printf("cudaMalloc __e FAIL! Code: %d\n", i); 

i = cudaMemcpy(devDatIn, PInData, SizeIn * sizeof(unsigned char), cudaMemcpyHostToDevice); 
if(i != cudaSuccess) 
printf(" cudaMemcpy __e FAIL! Code: %d\n", i); 
i = cudaMemcpy(devDatOut, POutData, SizeOut * sizeof(unsigned char), cudaMemcpyHostToDevice); 
if(i != cudaSuccess) 
printf(" cudaMemcpy __e FAIL! Code: %d\n", i); 

dim3 gridSize = dim3(1, 1, 1); 
dim3 blockSize = dim3(SizeIn, 1, 1); 

addMatrix<<<gridSize, blockSize>>>(devDatIn, devDatOut); 
if (i == cudaGetLastError()) 
{ 
printf("Error! %d\n", cudaGetLastError()); 
_getch; 
} 

cudaEvent_t syncEvent; 

cudaEventCreate(&syncEvent); 
cudaEventRecord(syncEvent, 0); 
cudaEventSynchronize(syncEvent); 

cudaMemcpy(POutData, devDatOut, SizeOut * sizeof(unsigned char), cudaMemcpyDeviceToHost); 

    cudaEventDestroy(syncEvent); 

i = WriteBmpFile(L"3840x2160_test2.bmp", iWidth, iHeight, 8, pDataOut.size(), pDataOut.data(), false); 
    if(i != 0) 
    printf(" cudaMemcpy __e FAIL! Code: %d\n", i); 

    cudaFree(devDatOut); 
    cudaFree(devDatIn); 

} 

EDIT 1:

Output image after editing

+0

おそらく 'SizeIn'は3840x2160 =約8のようなものです百万。 'SizeIn'が1024より大きい場合は、' dim3 blockSize = dim3(SizeIn、1、1); 'というCUDAブロックサイズを使用することはできません。さらに、カーネルを起動した直後の' cudaGetLastError() 'コールは、そのためにエラーを返すことがあります。あなたのカーネルも調整する必要があります。また、カーネルのデータへのインデックス付けも正しくありません。スレッドごとに3つずつストライドする必要があります。 –

+0

だから私はdim3 blockSize = dim3(1024、1、1)、右を使用する必要がありますか?その後、cudaGetLastError()は何も返しませんが、プログラマはまだ私に黒いイメージを与えます。私はちょうどカーネルの部分に何が間違っているかは分かりません。 コードを変更して正常に動作させることはできますか? – Generwp

答えて

2

コメントで見られるように、あなたはブロックごとにあまりにも多くのスレッドを起動し、打ち上げはおそらく失敗しているが、あなたのエラーチェック不完全で、あなたはそれを見ることができません。 カーネルを起動した後の適切なエラーチェックについては、this answerを参照してください。

ところで、これらすべてのスレッドを持つ1つのブロックではなく、少ないスレッドで複数のブロックを起動する必要があります。 たとえば、1024ブロックの2000ブロックにすることができます。私の現在のカードでは、1024スレッドは各ブロックでできる最大値なので、さらにスレッドが必要な場合はいくつかのブロックを起動し、一般的にはスレッドを少なくしてより多くのブロックを起動し、 占いの詳細についてはwith this presentationをご覧ください。

たとえば、合計で10,000ピクセルの場合、それぞれ500スレッドの20ブロックを起動できます。 あなたは、両方のために一次元でこれを行うことができます:

dim3 blocks(20, 1, 1); 
dim3 threads(500, 1, 1); 

myKernel<<<blocks, threads>>>(...); 

とほとんど変化が(正確にメモリ内の画像バッファ内の固有の線形インデックスに特定の各ブロック内のスレッドインデックスをマッピングするために、あなたのカーネルに必要になります)あなたの特定のプロジェクトでテストされていません、ブラウザでこれを書いたが、線形化は、古き良きペンで紙にそれを考えることによって理解することは非常に簡単です:

__global__ void addMatrix(unsigned char *DataOut, unsigned char *DataIn) 
{ 
    int idx = BlockIdx.x * BlockDim.x + threadIdx.x; 

    unsigned char average = (unsigned char)((DataIn[idx] + DataIn[idx + 1] + DataIn[idx + 2])/3); 

    DataOut[idx + 0] = average; 
    DataOut[idx + 1] = average; 
    DataOut[idx + 2] = average; 
} 
+0

お返事ありがとうございます!特にエラーや占有の場合。私はコードを編集しましたが、今は少し質問があります。 私は3840x2160イメージを持っており、スレッドの上限は1024です。しかし、使用できるブロック数はいくつですか?私は試しました * dim3ブロック(5000,1,1); * * dim3スレッド(1024,1,1); * また、私は同じイメージを取得するためにこのコードをカーネルで使用しようとしましたが、出力は期待とはかなり異なる。それのどこが悪いんだい?新しい出力イメージを投稿に追加しました。 * int idx = blockIdx.x * blockDim.x + threadIdx.x; * * DataOut [idx] = DataIn [idx]; * – Generwp

+0

(3840 * 2160)/ 1024 = 8100 =>だから私は8100各ブロックに1024スレッドの画像3840x2160を処理するブロックですか? – Generwp

+0

はい!しかし、覚えておいてください。**正確には** 8100です。 サイズに合わせて正しいコードが1024で割れます。あなたの部門がintでキャストして4.7を返す場合は4ブロックになりますが、実際にはすべてのピクセルを計算するのに5ブロックが必要になるため、結果は切り上げられます。 上級者へのラウンド方法については、この回答を参照してください。http://stackoverflow.com/a/2745086/6172231 **編集:**あなたが外出しないようにカーネルにif文が必要ですこの追加のブロックを起動すると、必要のないスレッドがいくつか作成されるため、配列内の境界の数が増えます。 – Taro