CHDK Wiki
Advertisement

Introduction[]

CHDK 1.4 adds the ability to read and manipulate the raw image data inside the raw script hook, before the CHDK raw and camera jpeg are saved. This can be used to calculate subsequent exposure or modify the image. A flexible alternative to the shot_histogram function is included.

Development thread http://chdk.setepontos.com/index.php?topic=11081.msg119265#msg119265

General usage[]

The core functions are provided in a library called rawop, which is available by default. Some auxiliary functions are provide in the lua module rawoplib.

To use rawop, you must

  • Ensure the camera is in a shooting mode with raw data available (get_raw_support() == true)
  • Set the raw hook, with a timeout sufficient for all the operations you want to perform
  • Start a shot using scripted key presses (not using the shoot() function)
  • Wait for the raw hook to become ready
  • Analyze and/or modify the raw data using the rawop functions
  • Call hook_raw.continue() to allow the shooting process to continue

Functions which access raw data are only valid inside the raw hook. If called when the raw hook is not active, they throw an error. These functions will also throw an error if valid raw data is known to be unavailable in the current shooting mode.

Functions for querying raw buffer characteristics[]

These functions may be called at any time, but some depend on values that can change between shots (currently on G1X only) so in general, it is recommended that they be called inside the hook. In future versions, more values may change at runtime.

rawop.get_cfa[]

cfa=rawop.get_cfa()

cfa: CFA pattern as a 32 bit interger, as used in DNG

rawop.get_cfa_offsets[]

cfa_offsets=rawop.get_cfa_offsets()

cfa_offsets: offsets of color filter elements with respect to an even valued x,y pair, in the form

{
 r={ y=1, x=0, },
 g1={ y=0, x=0, },
 b={ y=0, x=1, },
 g2={ y=1, x=1, },
}

rawop.get_bits_per_pixel[]

bpp=rawop.get_bits_per_pixel()

bpp: sensor bit depth. 10, 12, or 14 in currently supported cameras

rawop.get_raw_neutral[]

neutral=rawop.get_raw_neutral()

neutral: approximate raw value of a neutral grey target exposed with Canon AE. This is designed such that raw values can be expressed as an Ev offset from "correct" exposure, so raw_to_ev(neutral) = 0

This is not aware of CFA, it is based on an average of all color elements

NOTE on G1x, the value may change depending on ISO settings. The value is only updated when the raw hook is entered for the shot so for maximum portability, this function should only be called inside the raw hook.

rawop.get_black_level[]

blacklevel=rawop.get_black_level()

blacklevel: sensor black level value. This is theoretically the value of a pixels which has received no detectable light. However un-exposed pixels may have higher values due to sensor effects (hot pixels, dark current etc) and can also have lower values in some cases.

NOTE on G1x, the value may change depending on ISO settings. The value is only updated when the raw hook is entered for the shot so for maximum portability, this function should only be called inside the raw hook.

rawop.get_white_level[]

whitelevel=rawop.get_white_level()

whitelevel: sensor white level value (currently 2^bpp - 1 for all known sensors), the maximum value a pixel can have.

Functions for querying raw dimensions[]

The values returned by these functions do not currently change at runtime, but it is possible they could change with shooting mode in future versions.

Active area generally includes all of the sensor area known to contain image data. This often includes dark borders of pixels which contain recognizable image data that is not exposed the same as the majority of the sensor. JPEG area may be a better choice for whole scene measurements.

Active area coordinates in CHDK are guaranteed to be even. If the sensor active area physically occupies odd values, they will be excluded.

JPEG area represents the approximate area of the sensor used for the JPEG, but may not exactly match either the pixel dimensions or sensor area.

JPEG area generally will not include the dark borders that can affect active area, so jpeg area is a good choice for measuring the whole scene.

These JPEG area functions return sensor coordinates, unlike the DNG specification which gives default crop in terms of active area.

Both active area and JPEG area are defined in the port, and are not affected by the "Crop size" DNG menu option.

rawop.get_raw_width[]

width=rawop.get_raw_width()

width: The width of the sensor in pixels.

rawop.get_raw_height[]

height=rawop.get_raw_height()

height: The height of the sensor in pixels.

rawop.get_active_left[]

left=rawop.get_active_left()

left: X coordinate of the leftmost pixel in the active area

rawop.get_active_top[]

top=rawop.get_active_top()

top: y coordinate of the topmost pixel in the active area

rawop.get_active_width[]

width=rawop.get_active_width()

width: width of the active area, in pixels

rawop.get_active_height[]

height=rawop.get_active_height()

height: height of the active area, in pixels

rawop.get_jpeg_left[]

left=rawop.get_jpeg_left()

left: X coordinate of the leftmost pixel in the jpeg area

rawop.get_jpeg_top[]

top=rawop.get_jpeg_top()

top: y coordinate of the topmost pixel in the jpeg area

rawop.get_jpeg_width[]

width=rawop.get_jpeg_width()

width: width of the jpeg area, in pixels

rawop.get_jpeg_height[]

height=rawop.get_jpeg_height()

height: height of the jpeg area, in pixels

Functions for querying and modifying raw data[]

An error is generated if the these functions are called outside the raw hook, or in a shooting mode for which raw data is not available.

Functions with rgbg in the name operate on "quads" of pixels. Coordinates are truncated to even values, so the function will operate on the quad containing the specified coordinates. When rgbg values are specified, the second G will default to the value of the first if not given.

rawop.get_pixel[]

v=rawop.get_pixel(x,y)

v: raw value, or nil if out of bounds

rawop.set_pixel[]

rawop.set_pixel(x,y,v)

Sets pixel at x,y to value v. If x or y fall outside the sensor area, the call is ignored. If the v is larger than allowed by the camera bit depth, the behavior is unspecified.

rawop.get_pixels_rgbg[]

r,g1,b,g2=rawop.get_pixels_rgbg(x,y)

r,g1,b,g2: Red, green, blue and green values of the quad containing x,y, or nil if out of bounds.

rawop.set_pixels_rgbg[]

rawop.set_pixels_rgbg(x,y,r,g1,b[,g2])

Sets the values of the CFA quad containing x,y. If g2 is not specified, it is set to g1. If x or y fall outside the sensor area, the call is ignored. If the color valuers are larger than allowed by the camera bit depth, the behavior is unspecified.

rawop.fill_rect[]

rawop.fill_rect(x,y,width,height,val[,xstep[,ystep]])

Sets every step-th pixel of the specified rectangle to the specified value. Width and height out of bounds are clipped.

xstep defaults to 1, ystep defaults to xstep

Step 2 can be used with CFA offsets to fill RGB (see rawoplib fill_rect_rgbg)

This function can take a substantial amount of time when large areas are set (TODO example)

rawop.meter[]

mean_raw_val=rawop.meter(x,y,x_count,y_count,x_step,y_step)

mean_raw_val: average values of count pixels in x and y, sampled at step size step, or nil if the range is invalid or the total number of pixels could result in overflow

To prevent overflow, the total number of pixels must less unsigned_max / white_level. Limits are roughly

10 bpp = 4 Mpix
12 bpp = 1 Mpix
14 bpp = 256 Kpix

To meter larger numbers of pixels, use multiple calls and average the results

To meter R G B separately, use multiple meter calls with the appropriate CFA offset and even steps (see rawoplib meter_rgb and meter_rgbg)

To ensure all CFA colors are sampled in a single call, use odd step values.

This function can take a substantial amount of time when large counts are used (TODO example)

Functions for converting raw values for exposure calculation[]

rawop.raw_to_ev[]

ev=rawop.raw_to_ev(rawval[,scale])

ev: APEX-like "Ev" of the raw value, such that raw_to_ev(raw_neutral) == 0, and N*scale is N "stops" above or below neutral.

If rawval is <= to blacklevel, it is clamped to blacklevel + 1.

rawval > whitelevel is converted without any special treatment.

scale is optionally scales the APEX value. The default is 96, which results in values that can be used directly in calculations with the cameras normal APEX*96 exposure values. Use 1000 for imath APEX values or 96000 for APEX96 with imath.

NOTE on G1x, the result may change depending on ISO settings. The value is only updated when the raw hook is entered for the shot so for maximum portability, this function should only be called inside the raw hook.

rawop.ev_to_raw[]

rawval=rawop.ev_to_raw(ev[,scale])

Convert an APEX-like "Ev" value as described above into a raw value. No range checking is done.

scale optionally specifies a scale factor to divide the Ev value by before conversion. The default is 96 to be compatible with camera exposure parameters and raw_to_ev defaults.

NOTE on G1x, the result may change depending on ISO settings. The value is only updated when the raw hook is entered for the shot so for maximum portability, this function should only be called inside the raw hook.

Histogram functions[]

rawop provides flexible raw histogram functions through histogram objects. Multiple histograms can be created, and used to sample specified regions of the raw buffer.

Except for rawop.create_histogram, all histogram functions are provided by the object. These are referred to with the notation histo:'function_name' below, but the actual name will be the variable you assigned the histogram object to.

Histograms data is built by calling histo:update(). Querying a histogram with no data generates an error.

rawop.create_histogram[]

histo=rawop.create_histogram()

histo: A new histogram object.

histo:update[]

histo:update(top,left,width,height,xstep,ystep[,bits])

Update histogram data using specified area of raw buffer.

Bits specifies the bit depth of histogram. Defaults to camera bit depth, and must be <= camera bit depth. The amount of memory required for the histogram data is determined by bits.

An error is generated if the called outside the raw hook, or in a shooting mode for which raw data is not available.

To generate color specific histograms, use CFA offsets and even steps. To generate a histogram including all CFA channels, use odd steps.

This function may take a substantial amount of time when used on large numbers of pixels (TODO example)

Memory is allocated for the histogram data on the first update call, and re-allocated if bit depth changes. It is freed either by normal Lua garbage collection or an explicit call to histo:free()

histo:range[]

frac=histo:range(min,max[,'count'|scale])

frac: number of values in range, either as a fraction in parts per scale, or total count.

min, max: range of values to query, in raw values scaled to the bit depth specified in histo:update(). An error is generated if min > max or either falls outside the range of valid values for the histogram bit depth.

scale: defaults to 100, use the string 'count' for raw counts.

When large number of pixels are involved, calculations involving raw counts or very large scales may result in overflow.

An error is generated if the histogram does not contain data.

This function may take a non-trivial amount of time to execute.

histo:total_pixels[]

total=histo:total_pixels()

total: The total number of pixels sampled by the histogram.

An error is generated if the histogram does not contain data.

histo:bits[]

bits=histo:bits()

bits: The bit depth specified in the last call to histo:update().

An error is generated if the histogram does not contain data.

histo:free[]

histo:free()

Immediately free memory used by histogram data. histo:update must be called again to before any other functions. If histo:free() is not called, memory associated with the histogram will be freed along with the histogram object following normal Lua garbage collection rules.

rawoplib Lua module[]

The rawoplib module adds some additional convenence functions to rawop. To use it, just add

require'rawoplib'

to your script. The functions are added to the existing rawop table.

rawop.fill_rect_rgbg[]

rawop.fill_rect_rgbg(x,y,width,height,r,g1,b[,g2])

Fill the specified rectangle with the given color values.

rawop.rect_rgbg[]

rawop.rect_rgbg(x,y,width,height,linewidth,r,g1,b[,g2])

Draw an hollow rectangle with the given colors and line width.

rawop.rect[]

rawop.rect(x,y,width,height,linewidth,v,xstep,ystep)

Draw a hollow rectangle with a single color value

rawop.meter_rgbg[]

r,g1,b,g2=rawop.meter_rgbg(x,y,xcount,ycount,xstep,ystep)

Return the average value of pixels the each color channel in the specified area. Uses one rawop.meter call for each channel, using cfa offsets and the provided count and step values.

xstep and ystep must be even. count and step values are subject to the same limits as rawop.meter()

rawop.meter_rgb[]

r,g1,b=rawop.meter_rgbg(x,y,xcount,ycount,xstep,ystep)

Like rawop.meter_rgbg, but only measures the "first" green channel.

Performance notes[]

TODO

Examples[]

See CHDK/SCRIPTS/TEST/DRTEST.LUA and CHDK/SCRIPTS/TEST/RAWDRAW.LUA for some examples.

TODO some simple code samples

Known issues[]

TODO

Advertisement