Die mittlere Filterfunktion wird eine Maske über das Bild Punkt für Punkt passieren. Diese Maske hat die angegebenen Abmessungen (9x9 in Ihrem ursprünglichen Code). Der Ankerpunkt bestimmt, wie diese Maske für jedes Pixel positioniert wird. Wenn der Ankerpunkt 0,0 ist, wird die Maske wie folgt positioniert werden:
p**
***
***
wo p
die Pixelposition darstellt, und die Maskengröße ist 3x3. Für einen Ankerpunkt von 1,1, die Maskenpositionierung, pro Pixel, wäre:
***
*p*
***
Daher sehen wir, dass der Ankerpunkt, und die Maskengröße, eine gewisse Grenze um jedes Pixel zu bestimmen, welche muss für die Median-Filterfunktion zugänglich sein. Wenn wir uns mit Pixeln im Rand des Bildes beschäftigen, müssen wir sicherstellen, dass diese Grenze auf gültigen Pixeln landet.
Der Fall, mit dem Sie begonnen haben, eine 9x9-Maske und ein 0,0-Ankerpunkt, bedeutet, dass wir nur "extra" Pixel für die Grenze am "Ende" des Bildes benötigen. Daher ist die Änderung einfach: Beschränke die ROI-Höhe, um die letzten paar Zeilen des Bildes entsprechend der Maskenabmessung nicht zu verarbeiten.Für diesen Fall können wir einfach 10 von der ROI Höhe abziehen, und die Fehler weggehe
$ cat t1223.cu
//npp
#include "npp.h"
#include "nppi.h"
#include <iostream>
int main() {
//When the filter size is 9x9....
int imageWidth = 6592; //breaks if > 5914 && imageHeight = 4400
int imageHeight = 4400; //breaks if > 3946 && imageWidth = 6592
//Misc.
int bytesPerPixel = 2;
int totalPixels = imageWidth*imageHeight;
cudaError success2;
NppStatus success1;
//ROI for CUDA.
NppiSize cudaROI;
cudaROI.height = imageHeight-10;
cudaROI.width = imageWidth;
//Mask & Origin for CUDA.
NppiSize cudaMask; NppiPoint cudaAnchor;
cudaMask.height = 9; //filter size
cudaMask.width = 9;
cudaAnchor.x = 0;
cudaAnchor.y = 0;
//Step size.
int step = imageWidth * bytesPerPixel;
//Create a new "image".
unsigned short* image = new unsigned short[totalPixels];
for(int i=0; i<imageWidth; i++)
for(int j=0; j<imageHeight; j++)
image[j*imageWidth+i] = 10;
//Allocate mem on device.
Npp16u *dSrc, *dDst;
Npp8u *dBuf;
Npp32u bufferSize;
//This call always returns a bufferSize==0. That doesn't seem right...
success1 = nppiFilterMedianGetBufferSize_16u_C1R(cudaROI, cudaMask, &bufferSize);
std::cout << "get bufferSize returned: " << (int)success1 << std::endl;
std::cout << bufferSize << std::endl;
success2 = cudaMalloc((void**)&dBuf, bufferSize);
std::cout << "cudaMalloc 1 returned: " << (int)success2 << std::endl;
success2 = cudaMalloc((void**)&dSrc, totalPixels*sizeof(Npp16u));
std::cout << "cudaMalloc 2 returned: " << (int)success2 << std::endl;
success2 = cudaMalloc((void**)&dDst, totalPixels*sizeof(Npp16u));
std::cout << "cudaMalloc 3 returned: " << (int)success2 << std::endl;
//Copy host image to device.
success2 = cudaMemcpy(dSrc, image, totalPixels*sizeof(Npp16u), cudaMemcpyHostToDevice);
std::cout << "cudaMemcpy 1 returned: " << (int)success2 << std::endl;
//Copy source to destination.
success1 = nppiCopy_16u_C1R(dSrc, step, dDst, step, cudaROI);
std::cout << "npp Copy 1 returned: " << (int)success1 << std::endl;
//Filter.
success1 = nppiFilterMedian_16u_C1R(dSrc,
step,
dDst,
step,
cudaROI, cudaMask, cudaAnchor, dBuf);
std::cout << "npp Filter returned: " << (int)success1 << std::endl;
//Copy resultant back to host.
success2 = cudaMemcpy(image, dDst, totalPixels*sizeof(Npp16u), cudaMemcpyDeviceToHost);
std::cout << "cudaMemcpy 2 returned: " << (int)success2 << std::endl;
//Clean.
success2 = cudaFree(dBuf);
success2 = cudaFree(dSrc);
success2 = cudaFree(dDst);
delete image;
return 0;
}
$ nvcc -arch=sm_35 -o t1223 t1223.cu -lnppi
$ cuda-memcheck ./t1223
========= CUDA-MEMCHECK
get bufferSize returned: 0
0
cudaMalloc 1 returned: 0
cudaMalloc 2 returned: 0
cudaMalloc 3 returned: 0
cudaMemcpy 1 returned: 0
npp Copy 1 returned: 0
npp Filter returned: 0
cudaMemcpy 2 returned: 0
========= ERROR SUMMARY: 0 errors
$
Beachten Sie, dass, wenn der Ankerpunkt verschoben wurde (beispielsweise auf 4,4 anstelle von 0,0 im Fall oben), dann würde dies bedeuten, dass die "Grenz" -Pixel für ~ 5 Zeilen vor dem Start des Bildes verfügbar sein müssten. Wir können dies berücksichtigen, indem korrekt die ROI Einstellung und auch den Beginn der Verarbeitung ausgeglichen, indem Sie eine Zeile mit dem Quellenzeiger-Offset Zugabe zu den Median-Filter geleitet, etwa so:
success1 = nppiFilterMedian_16u_C1R(dSrc + 5*imageWidth,
Bitte beachte, dass ich nicht bin versucht, Um ein vollständiges Tutorial zur Median-Filterung zu geben, versuchen Sie nur das Problem zu identifizieren, das zum tatsächlichen Funktionsausfall führt. Die Filtergrenzen für die linke und die rechte Seite sind ebenfalls etwas, das Sie berücksichtigen sollten. An der linken und rechten Seite der Bildgrenzen können diese Pixelmaskengrenzen zu vorherigen oder nächsten Bildzeilen indizieren, wodurch das Bild "umhüllt" wird, möglicherweise mit ungeraden Effekten in den gefilterten Pixeln.
EDIT: Reagieren auf die neue Code-Veröffentlichung, scheint das Hauptproblem jetzt zu sein, dass Sie nicht verstehen, wie Sie das Bild versetzen.
In C/C++, wenn ich einen Zeiger habe, und ich möchte diesen Zeiger um eine bestimmte Anzahl von Elementen versetzen, füge ich einfach die Anzahl der Elemente, die ich durchsetzen möchte. Es gibt keine Notwendigkeit, dies durch Bytes zu skalieren. Wenn Sie das Offset-Beispiel, das ich oben angegeben hatte, studiert hätten, hätten Sie bemerkt, dass es keine Skalierung um Bytes gibt. Wenn wir um 5 Zeilen versetzt werden wollen, wird es nur 5 multipliziert mit der Bildbreite, wie oben angezeigt.
Außerdem haben Sie den cudaROI verwendet, um Ihre src> dst-Kopieroperation zu informieren, das macht für mich keinen Sinn, also habe ich das geändert. Schließlich habe ich den Code so modifiziert, dass er mit dem Anker in der Ecke oder dem Anker in der Mitte gebaut werden kann.
Hier ist eine Modifikation des Codes, die für mich kompiliert und läuft richtig, in beiden Anker Fällen:
$ cat t1225.cu
//npp
#include "npp.h"
#include "nppi.h"
#include "device_launch_parameters.h"
#include <iostream>
int main() {
//Image size.
int imageWidth = 6592;
int imageHeight = 4400;
//Misc.
int bytesPerPixel = 2;
int totalPixels = imageWidth*imageHeight;
int filterSize = 17;
int halfFilter = filterSize/2;
cudaError success2;
NppStatus success1;
//Mask & Origin for CUDA.
NppiSize cudaMask;
cudaMask.height = filterSize;
cudaMask.width = filterSize;
NppiPoint cudaAnchor;
#ifndef ANCHOR_CORNER
cudaAnchor.x = halfFilter;
cudaAnchor.y = halfFilter;
#else
cudaAnchor.x = 0;
cudaAnchor.y = 0;
#endif
NppiSize imgSize;
imgSize.width = imageWidth;
imgSize.height = imageHeight;
//ROI for CUDA.
int left = halfFilter;
int right = (imageWidth-1) - halfFilter;
int top = halfFilter;
int bot = (imageHeight-1) - halfFilter;
NppiSize cudaROI;
cudaROI.height = bot - top;
cudaROI.width = right - left;
//Step size.
int step = imageWidth * bytesPerPixel;
//Create a new "image".
unsigned short* image = new unsigned short[totalPixels];
for(int i=0; i<imageWidth; i++)
for(int j=0; j<imageHeight; j++)
image[j*imageWidth+i] = 10;
//Allocate mem on device.
Npp16u *dSrc, *dDst;
Npp8u *dBuf;
Npp32u bufferSize;
//This call always returns a bufferSize==0. That doesn't seem right...
success1 = nppiFilterMedianGetBufferSize_16u_C1R(cudaROI, cudaMask, &bufferSize);
std::cout << "get bufferSize returned: " << (int)success1 << std::endl;
std::cout << bufferSize << std::endl;
success2 = cudaMalloc((void**)&dBuf, bufferSize);
std::cout << "cudaMalloc 1 returned: " << (int)success2 << std::endl;
success2 = cudaMalloc((void**)&dSrc, totalPixels*sizeof(Npp16u));
std::cout << "cudaMalloc 2 returned: " << (int)success2 << std::endl;
success2 = cudaMalloc((void**)&dDst, totalPixels*sizeof(Npp16u));
std::cout << "cudaMalloc 3 returned: " << (int)success2 << std::endl;
//Copy host image to device.
success2 = cudaMemcpy(dSrc, image, totalPixels*sizeof(Npp16u), cudaMemcpyHostToDevice);
std::cout << "cudaMemcpy 1 returned: " << (int)success2 << std::endl;
//Copy source to destination.
success1 = nppiCopy_16u_C1R(dSrc, step, dDst, step, imgSize);
std::cout << "npp Copy 1 returned: " << (int)success1 << std::endl;
//Filter.
#ifndef ANCHOR_CORNER
Npp32u offset = top*imageWidth + left;
#else
Npp32u offset = 0;
#endif
success1 = nppiFilterMedian_16u_C1R( dSrc + offset,
step,
dDst + offset,
step,
cudaROI, cudaMask, cudaAnchor, dBuf);
std::cout << "npp Filter returned: " << (int)success1 << std::endl;
//Copy resultant back to host.
success2 = cudaMemcpy(image, dDst, totalPixels*sizeof(Npp16u), cudaMemcpyDeviceToHost);
std::cout << "cudaMemcpy 2 returned: " << (int)success2 << std::endl;
//Clean.
success2 = cudaFree(dDst);
success2 = cudaFree(dBuf);
success2 = cudaFree(dSrc);
delete image;
return 0;
}
$ nvcc -o t1225 t1225.cu -lnppi
$ cuda-memcheck ./t1225
========= CUDA-MEMCHECK
get bufferSize returned: 0
0
cudaMalloc 1 returned: 0
cudaMalloc 2 returned: 0
cudaMalloc 3 returned: 0
cudaMemcpy 1 returned: 0
npp Copy 1 returned: 0
npp Filter returned: 0
cudaMemcpy 2 returned: 0
========= ERROR SUMMARY: 0 errors
$ nvcc -DANCHOR_CORNER -o t1225 t1225.cu -lnppi
$ cuda-memcheck ./t1225
========= CUDA-MEMCHECK
get bufferSize returned: 0
0
cudaMalloc 1 returned: 0
cudaMalloc 2 returned: 0
cudaMalloc 3 returned: 0
cudaMemcpy 1 returned: 0
npp Copy 1 returned: 0
npp Filter returned: 0
cudaMemcpy 2 returned: 0
========= ERROR SUMMARY: 0 errors
bitte Code schreiben, die –
Der Medianfilter tatsächlich kompiliert ist nicht definiert (und illegale), wenn die Maske außen der definierte Eingangsbildbereich. Dies ist der Fall für die Randbereiche des Bildes, wenn Sie Ihren Code eingestellt haben. In der [äquivalenten intel ipp Dokumentation] (http://hpc.ipp.ac.cn/wp-content/uploads/2015/12/documentation_2016/en/ipp/common/ipp_manual/GUID-5D2F9418-E4F6-4F6C-B0F7 -B438CF28EA63.htm) Sie werden bemerken, dass es erforderlich ist, die Ausgabegröße zu reduzieren, um: "Um einen gültigen Vorgang zu gewährleisten, wenn Bildgrenzenpixel verarbeitet werden, sollte die Anwendung zusätzliche Rahmenpixel korrekt definieren" Sie verletzen diese Regel –
Robert, Ich habe einen Code gepostet, der kompiliert. Ich schaue immer noch, was Sie über Grenzpixel erwähnen. Im Moment versuche ich nur, den ROI zu reduzieren, so dass das Kopieren/Replizieren von Grenzen nicht erforderlich ist. –