Demosaicing Script (Python)
In this article:
We recommend reading Scripting in Application (Python) first to learn the basics of scripting.
Running the same script, Python is roughly 10 to 20 times slower than C#, but 5 to 10 times faster than JavaScript. The script runs again every time the image needs to be rendered, so please consider C# for a script which processes a large image.
Demosaicing Script
There is only one script in each demosaicing script, and it will be invoked one time every time when the image needs to be rendered. The script reads the mosaic from context.InputStream and writes the demosaiced BGRA pixels into context.OutputStream. The type of returned value is DemosaicingResult. Return DemosaicingResult.Default after interpolating the mosaic. The following is sample script to write the single color component provided by each pixel of the mosaic into all of the 3 color channels of that pixel, which produces a monochrome image:if context.Format != BitmapFormat.Bgra32:
raise Exception("Only 32-bit BGRA is supported by this script.")
mosaic = context.SelectNextSubMosaic()
while mosaic is not None:
width = mosaic.Width
height = mosaic.Height
rowBytes = mosaic.RowBytes
colorPattern = mosaic.ColorPattern
row = context.CreateByteArray(rowBytes)
for y in range(height):
mosaic.InputStream.Position = y * rowBytes
mosaic.InputStream.ReadExactly(row, 0, rowBytes)
components = colorPattern[y & 1]
for x in range(width):
offset = x * 4
sample = row[offset + int(components[x & 1])]
row[offset] = sample
row[offset + 1] = sample
row[offset + 2] = sample
row[offset + 3] = 255
mosaic.OutputStream.Position = y * rowBytes
mosaic.OutputStream.Write(row, 0, rowBytes)
mosaic = context.SelectNextSubMosaic()
return DemosaicingResult.Default
Each pixel of the mosaic provides only the single color component which ColorPattern reports for its position. The other color channels of that pixel are undefined and must never be read.
The sample above assumes that context.Format is Bgra32, so each pixel is 4 bytes. Each pixel is 8 bytes and each color channel is a 16-bit integer when the format is Bgra64.
Samples
The following is sample script to interpolate the mosaic by bilinear interpolation. It supports every pattern of Bayer Filter, it interpolates the mosaic in place, and it needs an image of Bgra64 format: You can import the downloaded file through the dialog of managing demosaicing scripts.Sub Mosaics
The mosaic of a 4x4 pattern of Bayer Filter is split into the 4 mosaics of the corresponding 2x2 pattern which its sub sampling positions carry, so that a script which interpolates a 2x2 mosaic is able to interpolate a 4x4 one as well. Each call of context.SelectNextSubMosaic() interleaves the sub mosaic interpolated by the previous call back into the image before it hands the next one out, and it returns None once every sub mosaic has been interpolated. The mosaic of a 2x2 pattern is not split, the context itself is handed out once as the only sub mosaic, so the same loop interpolates every pattern without checking BayerPattern first. The following are worth noticing while interpolating the sub mosaics:- The view of a sub mosaic and its streams are valid only until the next call of SelectNextSubMosaic().
- The width, the height and the number of bytes of a row of each sub mosaic are different from the ones of the image and from each other, so they must be read from the view inside the loop.
- BayerPattern and ColorPattern of every sub mosaic are the ones of the corresponding 2x2 pattern.
- Leaving the loop before it completes is allowed. The sub mosaic which was interpolated last is still interleaved back, and the rest of the image is left opaque black.
Interpolating the sub mosaics is optional. A script which declares a 4x4 pattern and never calls SelectNextSubMosaic() reads and writes the whole 4x4 mosaic through the members of context itself.
Context
The following are members of Context other than basic members:-
BayerPattern: BayerPattern
Pattern of Bayer Filter which the mosaic is rendered with. The following are values defined in BayerPattern:
- BGGR_2x2
- GBRG_2x2
- GRBG_2x2
- RGGB_2x2
- BGGR_4x4
- GBRG_4x4
- GRBG_4x4
- RGGB_4x4
-
ColorPattern: BayerPatternColorComponent[][]
Color component provided by each pixel in color block of the pattern of Bayer Filter. The 1st dimension is the position in vertical direction, the 2nd dimension is the position in horizontal direction. The array belongs to the script, modifying it affects nothing but the script itself. The following are values defined in BayerPatternColorComponent, and the value of each of them is the offset of its color channel in a BGRA pixel, so the component selects the channel of pixel directly:
- Blue
- Green
- Red
-
CreateByteArray(count: int): Array[byte]
Create an array of bytes for bulk reading from or writing to the streams provided by the context.
-
CreateUInt16Array(count: int): Array[ushort]
Create an array of 16-bit unsigned integers for bulk reading from or writing to the streams provided by the context.
-
CreateUInt32Array(count: int): Array[uint]
Create an array of 32-bit unsigned integers for bulk reading from or writing to the streams provided by the context.
-
CreateUInt64Array(count: int): Array[ulong]
Create an array of 64-bit unsigned integers for bulk reading from or writing to the streams provided by the context.
-
Format: BitmapFormat
Format of the buffers which the mosaic is read from and the demosaiced image is written to. The following are values defined in BitmapFormat:
- Bgra32
- Bgra64
-
Height: int
Height of image in pixels.
-
InputStream: System.IO.Stream
Stream to read the mosaic of image. The stream is read-only and fully seekable, and it is valid only during the demosaicing call. The pixel at (x, y) starts at y * RowBytes + x * (number of bytes of a pixel of Format).
-
OutputStream: System.IO.Stream
Stream to write the demosaiced image. The stream is fully seekable and readable, and it addresses its pixels exactly as InputStream does. It is valid only during the demosaicing call.
-
RenderingOptions: ImageRenderingOptions
Options of rendering the image. The following are members of ImageRenderingOptions:
- BlueGain: float
-
ByteOrdering: ByteOrdering
Byte ordering of source image data. The following are values defined in ByteOrdering:
- BigEndian
- LittleEndian
- GreenGain: float
- RedGain: float
-
RowBytes: int
Number of bytes of each row of the buffers.
-
SelectNextSubMosaic(): IMosaicView
Select the next sub mosaic of the image to be interpolated, or return None if every sub mosaic has been interpolated. Please refer to Sub Mosaics for more information. The following are members of IMosaicView, which report the sub mosaic instead of the image but are otherwise the same as the members of Context above:
- BayerPattern: BayerPattern
- ColorPattern: BayerPatternColorComponent[][]
- Format: BitmapFormat
- Height: int
- InputStream: System.IO.Stream
- OutputStream: System.IO.Stream
- RowBytes: int
- Width: int
-
Width: int
Width of image in pixels.
-
WorkingBufferStream: System.IO.Stream
Stream to read and write the buffer which the script keeps its own intermediate result in. The stream is fully seekable and it is valid only during the demosaicing call. Its length is the number of pixels of the image multiplied by the working buffer size per pixel which the algorithm defines, which is 0 unless the algorithm defines otherwise. Its content is undefined on entry and is not cleared, so every part of it has to be written before it is read, and writing past its end fails rather than growing it. The same stream is provided throughout the call, including while a sub mosaic is selected, and it is not divided between the sub mosaics.
Interacting with user is not supported inside a demosaicing script, because the script runs on a background thread every time when the image needs to be rendered.
Stream Extensions
The following members of StreamExtensions read and write arrays of unsigned integers, which are needed to read and write the 16-bit color channels of a Bgra64 image:-
ReadUInt16(stream: Stream, buffer: Array[ushort], offset: int, count: int): int
Read at most count 16-bit unsigned integers from the stream into the given array, and return the number of integers actually read. A returned number which is less than count means that the end of stream has been reached.
-
ReadUInt16Exact(stream: Stream, buffer: Array[ushort], offset: int, count: int): void
Read the given number of 16-bit unsigned integers from the stream into the given array, and throw EndOfStreamException if the end of stream is reached first.
- ReadUInt32(stream: Stream, buffer: Array[uint], offset: int, count: int): int
- ReadUInt32Exact(stream: Stream, buffer: Array[uint], offset: int, count: int): void
- ReadUInt64(stream: Stream, buffer: Array[ulong], offset: int, count: int): int
-
ReadUInt64Exact(stream: Stream, buffer: Array[ulong], offset: int, count: int): void
The 32-bit and 64-bit versions of the members above.
-
WriteUInt16(stream: Stream, buffer: Array[ushort], offset: int, count: int): void
Write the given number of 16-bit unsigned integers in the given array to the stream.
- WriteUInt32(stream: Stream, buffer: Array[uint], offset: int, count: int): void
-
WriteUInt64(stream: Stream, buffer: Array[ulong], offset: int, count: int): void
The 32-bit and 64-bit versions of WriteUInt16.
These members are available only as members of StreamExtensions which take the stream as their first argument, for example StreamExtensions.ReadUInt16Exact(context.InputStream, buffer, 0, count). Calling them as context.InputStream.ReadUInt16Exact(buffer, 0, count) does not work in Python.
Please use the arrays created by context.CreateUInt16Array and the other array factories with these members.