/// <summary> /// Configures the camera setting up required buffers. /// Allows separation of this time-intensive task from /// acquisition start. /// </summary> /// <param name="bufferCount">The number of frames requested as buffer</param> public void Configure(uint bufferCount) { //set up ring buffer pointers _ringBuffer = new IntPtr[bufferCount]; //create buffer list NIImaq.CheckError(NIImaq.imgCreateBufList(bufferCount, out _bufId)); //compute required buffer size uint bufSize = _width * _height * BytesPerPixel; //if this is a 16bit acquisition we pre-allocate an internal buffer //to allow us handing out 8bit images instead _imgDownsize = new Image16((int)Width, (int)Height); //Create our camera buffers and set up the buffer list //We set the list up as a ring buffer which means that the command //is NEXT for each buffer except the last one, where it will be loop for (uint i = 0; i < bufferCount; i++) { //Let imaq obtain the buffer memory NIImaq.CheckError(NIImaq.imgCreateBuffer(_sid, Buffer_Location.IMG_HOST_FRAME, bufSize, out _ringBuffer[i])); //assign buffer to our buffer list NIImaq.CheckError(NIImaq.imgSetBufferElement2(_bufId, i, BlItemType.IMG_BUFF_ADDRESS, _ringBuffer[i])); //tell the list about our buffer size NIImaq.CheckError(NIImaq.imgSetBufferElement2(_bufId, i, BlItemType.IMG_BUFF_SIZE, bufSize)); //Set the appropriate buffer command var bufCmd = i < (bufferCount - 1) ? BuffCommands.IMG_CMD_NEXT : BuffCommands.IMG_CMD_LOOP; NIImaq.CheckError(NIImaq.imgSetBufferElement2(_bufId, i, BlItemType.IMG_BUFF_COMMAND, bufCmd)); } //lock buffer list (supposed to be obsolote but example still does it...) NIImaq.CheckError(NIImaq.imgMemLock(_bufId)); //configure the session to use this buffer list NIImaq.CheckError(NIImaq.imgSessionConfigure(_sid, _bufId)); _configured = true; }
/// <summary> /// Produces an image in the ring buffer /// </summary> /// <param name="image">The image to write into the buffer</param> public void Produce(Image16 image) { if (_isDisposed) { throw new ObjectDisposedException("PrCoImageRingBuffer"); } if (image == null) { return; } if (image.Width != _imageWidth || image.Height != _imageHeight) { throw new ArgumentException("The produced image is not compatible with the buffer"); } lock (_accessLock) { //advance our production buffer "pointer" to the next place in the ring buffer _lastProduce = (_lastProduce + 1) % _nImages; //increment _imageIndex internally var temp = _imageIndex + 1; //copy image over ip.ippiCopy_16u_C1R(image.Image, image.Stride, _buffers[_lastProduce], _imageStride, new IppiSize(_imageWidth, _imageHeight)); //update the indices in the production place with the current image index _imageIndices[_lastProduce] = temp; //Image has been produced, update index and storage counter _imageIndex = temp; _storageCount++; //Signal waiting threads that we are about to release the lock Monitor.Pulse(_accessLock); } }
public Image16 copy() { global::System.IntPtr cPtr = libPhotoAssistantImageProcessingPINVOKE.Image16_copy(swigCPtr); Image16 ret = (cPtr == global::System.IntPtr.Zero) ? null : new Image16(cPtr, false); return(ret); }
/// <summary> /// Consumes an image from the ring buffer /// </summary> /// <param name="imageOut">The Image8 into which the consumed image should be copied</param> /// <param name="expectedIndex">The index we expect to recieve</param> /// <param name="stop">Wait handle to signal that the consumption thread is about to stop</param> /// <returns>True if the expected index could be consumed, false otherwise</returns> public bool Consume(Image16 imageOut, int expectedIndex, AutoResetEvent stop) { int indexRetrieved = Consume(imageOut, stop); if (indexRetrieved != expectedIndex) { System.Diagnostics.Debug.WriteLine("Ring buffer overflow. Expected image index {0} got image index {1}.", expectedIndex, indexRetrieved); return(false); } else { return(true); } }
public void FromImage16(Image16 im, float cMax) { if (im.Width != Width || im.Height != Height) { throw new ArgumentException("Width and Height must match"); } if (_scalingBuffer == null || _scalingBuffer.Length < im.Width * im.Height) { _scalingBuffer = new float[im.Width * im.Height]; fixed(float *pScalingBuffer = _scalingBuffer) { ip.ippiConvert_16u32f_C1R(im.Image, im.Stride, pScalingBuffer, 4 * im.Width, im.Size); ip.ippiScale_32f8u_C1R(pScalingBuffer, 4 * im.Width, Image, Stride, Size, 0, cMax); } }
/// <summary> /// Extracts a 16-bit image /// </summary> /// <param name="imageOut">The container to recieve the image</param> /// <param name="requestedFrame">The framenumber to request</param> /// <returns>The frame number actually retrieved from the buffer</returns> public uint Extract(Image16 imageOut, uint requestedFrame) { uint frameActual, indexActual; if (_bytesPerPixel == 1) { System.Diagnostics.Debug.WriteLine("Acquired 8 bit image into 16bit structure"); } NIImaq.CheckError(NIImaq.imgSessionCopyBufferByNumber(_sid, requestedFrame, (IntPtr)imageOut.Image, IMG_OVERWRITE_MODE.IMG_OVERWRITE_GET_NEWEST, out frameActual, out indexActual)); if (frameActual != requestedFrame) { System.Diagnostics.Debug.WriteLine("Requested frame {0}; obtained frame {1}", requestedFrame, frameActual); } _acquiredFrames++; return(frameActual); }
public static void Main(string[] args) { long startTime; Image16 im = new Image16(21000, 21000); Image16 im2 = new Image16(4096, 4096, 0x0); UIConsole.Log("Benchmark Draw"); startTime = LLTools.TimestampMS(); im.DrawImage(im2, 1024, 1024, true); UIConsole.Log($"Delta: {LLTools.TimestampMS() - startTime} ms"); UIConsole.Log("Benchmark Save PGM"); startTime = LLTools.TimestampMS(); im.SavePGM("test.pgm"); UIConsole.Log($"Delta: {LLTools.TimestampMS() - startTime} ms"); }
/// <summary> /// Consumes an image from the ring buffer /// </summary> /// <param name="imageOut">The Image8 into which the consumed image should be copied</param> /// <param name="stop">Wait handle to signal that the consumption thread is about to stop</param> /// <returns>The index of the retrieved image</returns> public int Consume(Image16 imageOut, AutoResetEvent stop) { int retval; if (_isDisposed) { throw new ObjectDisposedException("PrCoImageRingBuffer"); } if (imageOut == null) { throw new ArgumentNullException("imageOut"); } if (imageOut.Width != _imageWidth || imageOut.Height != _imageHeight) { throw new ArgumentException("The recieving image is not compatible with the buffer"); } lock (_accessLock) { while (_storageCount < 1) { //If we are told to stop then we throw an OperationCanceledException if (stop.WaitOne(0)) { throw new OperationCanceledException("Consume signaled to stop"); } //We wait for a pulse for 100ms. After that we independently try to reacquire the lock. //This way if the the producer has retired we are not indefinitely stuck on the wait and can listen //for a stop signal Monitor.Wait(_accessLock, 100); } //There is at least one image in storage, lets consume it //advance the consumption "pointer" to the next place in the buffer _lastConsume = (_lastConsume + 1) % _nImages; //copy image over ip.ippiCopy_16u_C1R(_buffers[_lastConsume], _imageStride, imageOut.Image, imageOut.Stride, new IppiSize(_imageWidth, _imageHeight)); //we want to return the index of the consumed image retval = _imageIndices[_lastConsume]; //decrement storage counter _storageCount--; } return(retval); }
protected virtual void Dispose(bool disposing) { if (IsDisposed) { return; } if (_captureRunning) { Stop(); } //Close interface and session NIImaq.imgClose(_sid, true); NIImaq.imgClose(_ifid, true); if (_imgDownsize != null) { _imgDownsize.Dispose(); _imgDownsize = null; } }
internal static global::System.Runtime.InteropServices.HandleRef getCPtr(Image16 obj) { return((obj == null) ? new global::System.Runtime.InteropServices.HandleRef(null, global::System.IntPtr.Zero) : obj.swigCPtr); }