2017-05-23 5 views
1

ich ein pycuda Programm hier haben, die von der Kommandozeile in einem Bild liest und speichert eine Version zurück mit den invertierten Farben:pyCuda, Fragen mehrere einzelne Variable Argumente Senden

import pycuda.autoinit 
import pycuda.driver as device 
from pycuda.compiler import SourceModule as cpp 

import numpy as np 
import sys 
import cv2 

modify_image = cpp(""" 
__global__ void modify_image(int pixelcount, unsigned char* inputimage, unsigned char* outputimage) 
{ 
    int id = threadIdx.x + blockIdx.x * blockDim.x; 
    if (id >= pixelcount) 
    return; 

    outputimage[id] = 255 - inputimage[id]; 
} 
""").get_function("modify_image") 

print("Loading image") 

image = cv2.imread(sys.argv[1], cv2.IMREAD_UNCHANGED).astype(np.uint8) 

print("Processing image") 

pixels = image.shape[0] * image.shape[1] 
newchannels = [] 
for channel in cv2.split(image): 
    output = np.zeros_like(channel) 
    modify_image(
    device.In(np.int32(pixels)), 
    device.In(channel), 
    device.Out(output), 
    block=(1024,1,1), grid=(pixels // 1024 + 1, 1)) 
    newchannels.append(output) 
finalimage = cv2.merge(newchannels) 

print("Saving image") 

cv2.imwrite("processed.png", finalimage) 

print("Done") 

Es funktioniert völlig in Ordnung, auch auf größere Bilder. Beim Versuch, die Funktionalität des Programms zu erweitern, stieß ich jedoch auf ein wirklich seltsames Problem, bei dem das Hinzufügen eines zweiten Variablenarguments zum Kernel dazu führt, dass das Programm vollständig fehlschlägt und einfach ein vollständig schwarzes Bild gespeichert wird. Der folgende Code funktioniert nicht.

import pycuda.autoinit 
import pycuda.driver as device 
from pycuda.compiler import SourceModule as cpp 

import numpy as np 
import sys 
import cv2 

modify_image = cpp(""" 
__global__ void modify_image(int pixelcount, int width, unsigned char* inputimage, unsigned char* outputimage) 
{ 
    int id = threadIdx.x + blockIdx.x * blockDim.x; 
    if (id >= pixelcount) 
    return; 

    outputimage[id] = 255 - inputimage[id]; 
} 
""").get_function("modify_image") 

print("Loading image") 

image = cv2.imread(sys.argv[1], cv2.IMREAD_UNCHANGED).astype(np.uint8) 

print("Processing image") 

pixels = image.shape[0] * image.shape[1] 
newchannels = [] 
for channel in cv2.split(image): 
    output = np.zeros_like(channel) 
    modify_image(
    device.In(np.int32(pixels)), 
    device.In(np.int32(image.shape[0])), 
    device.In(channel), 
    device.Out(output), 
    block=(1024,1,1), grid=(pixels // 1024 + 1, 1)) 
    newchannels.append(output) 
finalimage = cv2.merge(newchannels) 

print("Saving image") 

cv2.imwrite("processed.png", finalimage) 

print("Done") 

wo der einzige Unterschied auf zwei Zeilen ist, der Kernel-Header und es ist Aufruf. Der eigentliche Code des Kerns selbst ist unverändert, und dennoch bricht diese kleine Addition das Programm vollständig durch. Weder der Compiler noch der Interpreter werfen Fehler. Ich habe keine Ahnung, wie ich anfangen kann, es zu debuggen, und bin völlig verwirrt.

Antwort

1

Die device.In und Verwandten sind für die Verwendung mit Objekten, die die Python-Puffer-Protokolle (wie numpy Arrays) unterstützen. Die Ursache Ihres Problems besteht darin, sie für die Übertragung von Nichtpufferobjekten zu verwenden.

Übergeben Sie einfach Ihre Skalare mit dem richtigen numpy dtype direkt an Ihren Kernel-Aufruf. Verwenden Sie nicht device.In. Die Tatsache, dass dies im Originalfall funktionierte, war ein kompletter Unfall

+0

Ah, okay danke. Das macht sehr viel Sinn. Ich dachte, die In-und Out-Anrufe waren in allen Fällen notwendig, aber ich denke nicht – Maurdekye

0

Okay, indem ich die Variablenargumente zu Zeigern im Kernel ändere, reparierte ich den Code, ich bin mir nicht sicher, wie oder warum. Hier ist die modifizierte Version des Kernels;

__global__ void modify_image(int* pixelcount, int* width, unsigned char* inputimage, unsigned char* outputimage) 
{ 
    int id = threadIdx.x + blockIdx.x * blockDim.x; 
    if (id >= *pixelcount) 
    return; 

    outputimage[id] = 255 - inputimage[id]; 
} 

Der Rest des Codes ist unverändert. Wenn jemand erklären möchte, warum dies eine erfolgreiche Lösung ist, würde ich es sehr begrüßen.

Verwandte Themen