Image processing with OpenCL.NET - opencl
I'm trying to do image processing on the GPU with .NET. I've downloaded OpenCL.NET wrapper. It has some good samples, but I cannot find a way to load an image to the GPU and read the processed image back. What do I have to do?
After setting up the context, do the following:
public void ImagingTest (string inputImagePath, string outputImagePath)
{
Cl.ErrorCode error;
//Load and compile kernel source code.
string programPath = Environment.CurrentDirectory + "/../../ImagingTest.cl"; //The path to the source file may vary
if (!System.IO.File.Exists (programPath)) {
Console.WriteLine ("Program doesn't exist at path " + programPath);
return;
}
string programSource = System.IO.File.ReadAllText (programPath);
using (Cl.Program program = Cl.CreateProgramWithSource(_context, 1, new[] { programSource }, null, out error)) {
CheckErr(error, "Cl.CreateProgramWithSource");
//Compile kernel source
error = Cl.BuildProgram (program, 1, new[] { _device }, string.Empty, null, IntPtr.Zero);
CheckErr(error, "Cl.BuildProgram");
//Check for any compilation errors
if (Cl.GetProgramBuildInfo (program, _device, Cl.ProgramBuildInfo.Status, out error).CastTo<Cl.BuildStatus>()
!= Cl.BuildStatus.Success) {
CheckErr(error, "Cl.GetProgramBuildInfo");
Console.WriteLine("Cl.GetProgramBuildInfo != Success");
Console.WriteLine(Cl.GetProgramBuildInfo(program, _device, Cl.ProgramBuildInfo.Log, out error));
return;
}
//Create the required kernel (entry function)
Cl.Kernel kernel = Cl.CreateKernel(program, "imagingTest", out error);
CheckErr(error, "Cl.CreateKernel");
int intPtrSize = 0;
intPtrSize = Marshal.SizeOf(typeof(IntPtr));
//Image's RGBA data converted to an unmanaged[] array
byte[] inputByteArray;
//OpenCL memory buffer that will keep our image's byte[] data.
Cl.Mem inputImage2DBuffer;
Cl.ImageFormat clImageFormat = new Cl.ImageFormat(Cl.ChannelOrder.RGBA, Cl.ChannelType.Unsigned_Int8);
int inputImgWidth, inputImgHeight;
int inputImgBytesSize;
int inputImgStride;
//Try loading the input image
using (FileStream imageFileStream = new FileStream(inputImagePath, FileMode.Open) ) {
System.Drawing.Image inputImage = System.Drawing.Image.FromStream( imageFileStream );
if (inputImage == null) {
Console.WriteLine("Unable to load input image");
return;
}
inputImgWidth = inputImage.Width;
inputImgHeight = inputImage.Height;
System.Drawing.Bitmap bmpImage = new System.Drawing.Bitmap(inputImage);
//Get raw pixel data of the bitmap
//The format should match the format of clImageFormat
BitmapData bitmapData = bmpImage.LockBits( new Rectangle(0, 0, bmpImage.Width, bmpImage.Height),
ImageLockMode.ReadOnly, PixelFormat.Format32bppArgb);//inputImage.PixelFormat);
inputImgStride = bitmapData.Stride;
inputImgBytesSize = bitmapData.Stride * bitmapData.Height;
//Copy the raw bitmap data to an unmanaged byte[] array
inputByteArray = new byte[inputImgBytesSize];
Marshal.Copy(bitmapData.Scan0, inputByteArray, 0, inputImgBytesSize);
//Allocate OpenCL image memory buffer
inputImage2DBuffer = Cl.CreateImage2D(_context, Cl.MemFlags.CopyHostPtr | Cl.MemFlags.ReadOnly, clImageFormat,
(IntPtr)bitmapData.Width, (IntPtr)bitmapData.Height,
(IntPtr)0, inputByteArray, out error);
CheckErr(error, "Cl.CreateImage2D input");
}
//Unmanaged output image's raw RGBA byte[] array
byte[] outputByteArray = new byte[inputImgBytesSize];
//Allocate OpenCL image memory buffer
Cl.Mem outputImage2DBuffer = Cl.CreateImage2D(_context, Cl.MemFlags.CopyHostPtr | Cl.MemFlags.WriteOnly, clImageFormat,
(IntPtr)inputImgWidth, (IntPtr)inputImgHeight, (IntPtr)0, outputByteArray, out error);
CheckErr(error, "Cl.CreateImage2D output");
//Pass the memory buffers to our kernel function
error = Cl.SetKernelArg(kernel, 0, (IntPtr)intPtrSize, inputImage2DBuffer);
error |= Cl.SetKernelArg(kernel, 1, (IntPtr)intPtrSize, outputImage2DBuffer);
CheckErr(error, "Cl.SetKernelArg");
//Create a command queue, where all of the commands for execution will be added
Cl.CommandQueue cmdQueue = Cl.CreateCommandQueue(_context, _device, (Cl.CommandQueueProperties)0, out error);
CheckErr(error, "Cl.CreateCommandQueue");
Cl.Event clevent;
//Copy input image from the host to the GPU.
IntPtr[] originPtr = new IntPtr[] { (IntPtr)0, (IntPtr)0, (IntPtr)0 }; //x, y, z
IntPtr[] regionPtr = new IntPtr[] { (IntPtr)inputImgWidth, (IntPtr)inputImgHeight, (IntPtr)1 }; //x, y, z
IntPtr[] workGroupSizePtr = new IntPtr[] { (IntPtr)inputImgWidth, (IntPtr)inputImgHeight, (IntPtr)1 };
error = Cl.EnqueueWriteImage(cmdQueue, inputImage2DBuffer, Cl.Bool.True, originPtr, regionPtr, (IntPtr)0, (IntPtr)0, inputByteArray, 0, null, out clevent);
CheckErr(error, "Cl.EnqueueWriteImage");
//Execute our kernel (OpenCL code)
error = Cl.EnqueueNDRangeKernel(cmdQueue, kernel, 2, null, workGroupSizePtr, null, 0, null, out clevent);
CheckErr(error, "Cl.EnqueueNDRangeKernel");
//Wait for completion of all calculations on the GPU.
error = Cl.Finish(cmdQueue);
CheckErr(error, "Cl.Finish");
//Read the processed image from GPU to raw RGBA data byte[] array
error = Cl.EnqueueReadImage(cmdQueue, outputImage2DBuffer, Cl.Bool.True, originPtr, regionPtr,
(IntPtr)0, (IntPtr)0, outputByteArray, 0, null, out clevent);
CheckErr(error, "Cl.clEnqueueReadImage");
//Clean up memory
Cl.ReleaseKernel(kernel);
Cl.ReleaseCommandQueue(cmdQueue);
Cl.ReleaseMemObject(inputImage2DBuffer);
Cl.ReleaseMemObject(outputImage2DBuffer);
//Get a pointer to our unmanaged output byte[] array
GCHandle pinnedOutputArray = GCHandle.Alloc(outputByteArray, GCHandleType.Pinned);
IntPtr outputBmpPointer = pinnedOutputArray.AddrOfPinnedObject();
//Create a new bitmap with processed data and save it to a file.
Bitmap outputBitmap = new Bitmap(inputImgWidth, inputImgHeight, inputImgStride, PixelFormat.Format32bppArgb, outputBmpPointer);
outputBitmap.Save(outputImagePath, System.Drawing.Imaging.ImageFormat.Png);
pinnedOutputArray.Free();
}
}
OpenCL kernel used in this example:
__kernel void imagingTest(__read_only image2d_t srcImg,
__write_only image2d_t dstImg)
{
const sampler_t smp = CLK_NORMALIZED_COORDS_FALSE | //Natural coordinates
CLK_ADDRESS_CLAMP_TO_EDGE | //Clamp to zeros
CLK_FILTER_LINEAR;
int2 coord = (int2)(get_global_id(0), get_global_id(1));
uint4 bgra = read_imageui(srcImg, smp, coord); //The byte order is BGRA
float4 bgrafloat = convert_float4(bgra) / 255.0f; //Convert to normalized [0..1] float
//Convert RGB to luminance (make the image grayscale).
float luminance = sqrt(0.241f * bgrafloat.z * bgrafloat.z + 0.691f * bgrafloat.y * bgrafloat.y + 0.068f * bgrafloat.x * bgrafloat.x);
bgra.x = bgra.y = bgra.z = (uint) (luminance * 255.0f);
bgra.w = 255;
write_imageui(dstImg, coord, bgra);
}
*Complete article available at codeproject.com
Related
Printing PDF doc to esc/pos Thermal printer
We are developing a POS APP using xamarin.forms, in that we need to print the receipt to an esc/pos thermal printer connected via LAN. We have multi language support with the App, printing multiple language with the esc/pos commands by changing code page works perfectly. But its working for some supported language only, for other language its printing garbage characters(unreadable ones). so we thought of creating a pdf for the receipt and print that one. we tried to create the pdf and then convert to bitmap and then send to the printer by using esc pos commands, but its not printing anything. public BitImage(String filename) { Java.IO.File file = new Java.IO.File(filename); var pdfRenderer = new PdfRenderer(ParcelFileDescriptor.Open(file, ParcelFileMode.ReadOnly)); PdfRenderer.Page page = pdfRenderer.OpenPage(0); Bitmap bmp = Bitmap.CreateBitmap(page.Width, page.Height, Bitmap.Config.Argb8888); page.Render(bmp, null, null, PdfRenderMode.ForPrint); load(bmp); } private void load(Bitmap bmp) { int w = bmp.Width; int h = bmp.Height; int bw = (w + 7) / 8; if (bw > 255) bw = 255; int bh = h / 8; if (bh > 24) { bh = 24; } initData(bw * 8, bh * 8); for (int y = 0; y < h; y++) { for (int x = 0; x < w; x++) { if (bmp.GetPixel(x, y) == Color.Black) setPixel(x, y); } } } private void initData(int w, int h) { width = w; height = h; pitch = h / 8; data = new byte[w * pitch]; } private void setPixel(int x, int y) { if (x >= width || y >= height) { return; } int mask = (0x0080 >> (y % 8)); data[(x * pitch) + (y / 8)] |= (byte)mask; } public void PrintData() { byte[] CMD_INIT = { 0x1B, 0x40 }; byte[] CMD_UPLOAD_IMAGE = { 0x1D, 0x2A, 0, 0 }; byte[] CMD_PRINT_IMAGE = { 0x1D, 0x2F, 0 }; byte[] CMD_CUT = { 0x1D, 0x56, 0x01 }; CMD_UPLOAD_IMAGE[2] = (byte)(width / 8); CMD_UPLOAD_IMAGE[3] = (byte)(height / 8); #region Print Via Lan Socket pSocket = new Socket(SocketType.Stream, ProtocolType.IP); pSocket.SendTimeout = 1500; pSocket.Connect("192.168.15.168", 9100); pSocket.Send(CMD_INIT); pSocket.Send(CMD_UPLOAD_IMAGE); pSocket.Send(data); pSocket.Send(CMD_PRINT_IMAGE); pSocket.Send(CMD_CUT); pSocket.Close(); #endregion } Please help me, whether i am doing it in correct way? or is there any better way to do the same?
You can use libraries like SkiaSharp to make Image/PDF from your data in any language and print them properly using any printer. I've created a sample to demonstrate how to print images properly with ESC\POS printers in C#: GitHub code repo
Request was aborted
I tried to split large file into small 4KB chunks and send each chunks to oracle cloud but request is aborting. Please check the splitting code whether it is correct or not or am I doing wrong something else. FileStream rdr = new FileStream(fileToUpload, FileMode.Open, FileAccess.Read); byte[] inData = new byte[4096]; long chunkSize= rdr.Length; long chunkBytesToRead = chunkSize; using (Stream reqStream = request.GetRequestStream()) { while (rdr.Position < rdr.Length) { int chunkBytesRead = 0; int maxread = 4096; while (chunkBytesRead < chunkSize) { int bytesRead = rdr.Read(inData,0,maxread); if (bytesRead == 0) { break; } reqStream.Write(inData, 0, bytesRead); chunkBytesToRead -= bytesRead; if (chunkBytesToRead < 4096) maxread = (int)chunkBytesToRead; chunkBytesRead += bytesRead; } } reqStream.Close(); }
How convert a raw image stored in a byte array to a rgb image with opencv and Java
i am working in the preview of a fingerprint scaner using id3Fingerprint sdk and OpenCV. If i just show the preview from the id3fingerprint sdk all is fine, but if i load it to a Mat object of OpenCV in order to draw some rectangles in the image then: 1.- The fingerprints are displayed in right form but the rectangles are displayed as lines or pixels in random x,y location. 2.- The rectangles are displayed in right form but the fingerprints are displayed "blured" (look the image attached).fingerprints are blured I think, my problem is when i convert the raw grayscale image (a byte array from the id3fingerprint sdk) to a RGB or RGBA image. private void showPreview2(FingerImage image){ int height = 750; int width = 750; int currentWidth = 0; int currentHeight = 0; try { currentWidth = image.getWidth(); currentHeight = image.getHeight(); } catch (FingerException ex) { Logger.getLogger(CallingID3Example.class.getName()).log(Level.SEVERE, null, ex); } byte[] pixels = image.getPixels(); Mat dest = new Mat(); Mat source = new Mat(); Mat source2 = null; source2 = new Mat(currentWidth, currentHeight, CvType.CV_8UC1); source2.put(0, 0, pixels); MatOfByte pix = new MatOfByte(); Imgcodecs.imencode(".bmp", source2, pix); source2.put(0, 0, pix.toArray()); Imgproc.cvtColor(source2, source, Imgproc.COLOR_GRAY2RGBA); try { int i=0; for(FingerImage finger : image.getSegments()){ Scalar color; color = new Scalar(0, 250,0); FingerBounds bound = image.getSegmentBounds()[i]; Imgproc.rectangle(source, new Point(bound.topLeft.x, bound.topLeft.y), new Point(bound.bottomRight.x, bound.bottomRight.y), color, 3); double[] pixelTest; pixelTest = source.get(bound.topLeft.x, bound.topLeft.y); i++; } } catch (FingerException ex) { Logger.getLogger(CallingID3Example.class.getName()).log(Level.SEVERE, null, ex); } gc = canvas.getGraphicsContext2D(); WritableImage writableImage = loadImage(source); imageView.setImage(writableImage); } private WritableImage loadImage(Mat matrix) { // Encoding the image MatOfByte matOfByte = new MatOfByte(); Imgcodecs.imencode(".bmp", matrix, matOfByte); // Storing the encoded Mat in a byte array byte[] byteArray = matOfByte.toArray(); // Displaying the image InputStream in = new ByteArrayInputStream(byteArray); BufferedImage bufImage = null; try { bufImage = ImageIO.read(in); } catch (IOException ex) { } // Creating the Writable Image WritableImage writableImage = SwingFXUtils.toFXImage(bufImage, null); return writableImage; } Thanks for your answer.
You could try something like this: // You need to know width/height of the image int width = 0; int height = 0; byte[] imageSrc = null;// // Convert 8bit greyscale byte array to RGBA byte array. byte[] imageRGBA = new byte[imageSrc.length * 4]; int i; for (i = 0; i < imageSrc.length; i++) { imageRGBA[i * 4] = imageRGBA[i * 4 + 1] = imageRGBA[i * 4 + 2] = ((byte) ~imageSrc[i]); // Invert the source bits imageRGBA[i * 4 + 3] = -1;// 0xff, that's the alpha. } // Convert RGBA byte array to PNG int samplesPerPixel = 4; int[] bandOffsets = {0,1,2,3}; // RGBA order byte[] bgraPixelData = new byte[width * height * samplesPerPixel]; DataBuffer buffer = new DataBufferByte(bgraPixelData, bgraPixelData.length); WritableRaster raster = Raster.createInterleavedRaster(buffer, width, height, samplesPerPixel * width, samplesPerPixel, bandOffsets, null); ColorModel colorModel = new ComponentColorModel(ColorSpace.getInstance(ColorSpace.CS_sRGB), true, false, Transparency.TRANSLUCENT, DataBuffer.TYPE_BYTE); BufferedImage image = new BufferedImage(colorModel, raster, colorModel.isAlphaPremultiplied(), null); System.out.println("image: " + image); // Should print: image: BufferedImage#<hash>: type = 0 ... ImageIO.write(image, "PNG", new File(path)); Update To draw rectangle on image: BufferedImage image = ... Graphics2D graph = img.createGraphics(); graph.setColor(Color.BLACK); graph.fill(new Rectangle(x, y, width, height)); graph.dispose(); ImageIO.write(image, "PNG", new File(path));
getting out of memory exception while using fileStream
I am facing an Issue while uploading file from a web page to server. It works fine for files upto 200 MB, but starts throwing out of memory exception. Could you please help me I have pasted the code below private void UploadToServer(HttpPostedFile oHttpPostedFile) { string CalCheckSum = string.Empty; try { string FileName = getFileName(oHttpPostedFile.FileName.Trim()); if (File.Exists(Server.MapPath("Upload") + "\\" + System.IO.Path.GetFileName(FileName))) { File.Delete(Server.MapPath("Upload") + "\\" + System.IO.Path.GetFileName(FileName)); } string serverFilePath = Server.MapPath("Upload") + "\\" + System.IO.Path.GetFileName(FileName); FileStream fs = new FileStream(serverFilePath, FileMode.CreateNew); string strFileFormName = serverFilePath; // Uri oUri = new Uri(strUrl); // DFB: Upload goes into stream Stream myStream = oHttpPostedFile.InputStream; string _name = oHttpPostedFile.FileName; string _contentType = oHttpPostedFile.ContentType; // DFB: Create buffer for stream Byte[] myBuffer; myBuffer = new byte[10240]; if (myStream.Length == 0) { //Zero Bytes file Can not be processed CalCheckSum = string.Empty; return; } else if (myStream.Length > 10240) myBuffer = new byte[10240]; else myBuffer = new byte[myStream.Length]; StringBuilder filecontent = new StringBuilder(); int fileLength = (int)myStream.Length; int length = (int)myStream.Length / myBuffer.Length + 1; int lastPacketLength = (int)myStream.Length % 10240; int count = 1; while (myStream.Read(myBuffer, 0, myBuffer.Length) > 0) { if (count == length) fs.Write(myBuffer, 0, lastPacketLength); else fs.Write(myBuffer, 0, myBuffer.Length); count++; } fs.Close(); fs.Dispose(); myStream.Dispose(); myBuffer = null; myStream = null; FileStream fileStream = File.OpenRead(serverFilePath); byte[] pbytCombinedArrays = new byte[fileLength]; int numBytesToRead = fileLength; int numBytesRead = 0; while (numBytesToRead > 0) { // Read may return anything from 0 to numBytesToRead. int n = fileStream.Read(pbytCombinedArrays, numBytesRead, numBytesToRead); // Break when the end of the file is reached. if (n == 0) break; numBytesRead += n; numBytesToRead -= n; } fileStream.Dispose(); fileStream.Close(); }
You get the exception because you are trying to allocate more memory than is allowed for the application. Web applications are generally limited to about 300 MB. The solution would be to avoid reading the entire file into memory. It's simply too large for a web application to handle all at once.
Transmission parameters in to the function in openCL
Have following kernel function: private static String programSource = "__kernel void sampleKernel(__global float *Y, __global float *param) " + "{ int index = get_global_id(0); " + " Y[index]=param[0]-Y[index]/param[1]-param[2]; " + "} "; First argument "Y" works perfect, but second parameter "param" works non correct, I receive null values . Second parametr must be a array and consists from 3 cells. Fragment of code with the transmission parameters: float[] arr_params = new float[3]; arr_params[0] = (float) h_c; arr_params[1] = (float) sy; arr_params[2] = (float) dy; //pointers Pointer Pvy = Pointer.to(vy); Pointer Parr_params = Pointer.to(arr_params); cl_mem memObjects[] = new cl_mem[2]; memObjects[0] = clCreateBuffer(context, CL_MEM_READ_WRITE, Sizeof.cl_float * vy.length, Pvy, null); memObjects[1] = clCreateBuffer(context, CL_MEM_READ_ONLY, Sizeof.cl_float * arr_params.length, Parr_params, null); // Set the arguments for the kernel clSetKernelArg(kernel, 0, Sizeof.cl_mem, Pointer.to(memObjects[0])); clSetKernelArg(kernel, 1, Sizeof.cl_mem, Pointer.to(memObjects[1])); // Set the work-item dimensions long global_work_size[] = new long[]{vy.length}; long local_work_size[] = new long[]{1}; // Execute the kernel clEnqueueNDRangeKernel(commandQueue, kernel, 1, null, global_work_size, local_work_size, 0, null, null); // Read the output data clEnqueueReadBuffer(commandQueue, memObjects[0], CL_TRUE, 0, vy.length * Sizeof.cl_float, Pvy, 0, null, null); // Release kernel, program, and memory objects clReleaseMemObject(memObjects[0]); clReleaseMemObject(memObjects[1]);
The second buffer is all zeros because, in the clCreateBuffer call, you haven't told OpenCL where to get the data. Use CL_MEM_USE_HOST_PTR or CL_MEM_COPY_HOST_PTR.