snibgo's ImageMagick pages

Mosaicing

We can make Bayer (mosaic) images from ordinary colour images.

A mosaiced (Bayer) image contains one channel per pixel, where the value represents either red or green or blue, according to the location of the pixel within the array.

Demosaicing is the process of creating a 3-channel colour image from a mosaiced (Bayer) image. This is often done inside the camera, but can be done in a computer. Demosaicing trebles the amount of data in an image by some interpolation process that guesses the correct colours for the two values that are missing from each pixel. Many methods are available for demosaicing; there are many possible results, each arguably "correct". See my Demosaicing page.

We can do the inverse process, and mosaic a colour image. That is, we take a three-channel colour image and remove two-thirds of the data so each pixel then contains only one of the three channels. This may be useful in a round-trip evaluation of different demosaicing methods: we know a Bayer image and a desired result, so can evaluate how accurate the demosaiced results are.

I'm not sure how useful these tests are. If the colour image used is an ordinary photograph, then it has probably been demosaiced from a Bayer image. So the evaluation will determine which demosaicing method most closely emulates the original demosaicing process, rather than which method is the best for this image.

Sample input

set SRC=dm_cars_demos.jpg
dm_cars_demos.jpg

The method

From the input three-channel colour image, we make a grayscale one-channel image where each pixel represents the value that was in the red, green or blue channel.

We do this with three masks.

%IM%convert ^
  -size 2x2 xc:black ^
  -fill White -draw "point 1,0" ^
  +write mos_msk_G0.png ^
  -roll +0+1 +write mos_msk_B.png ^
  -roll -1+0 +write mos_msk_G1.png ^
  NULL:
mos_msk_G0.png mos_msk_G1.png mos_msk_B.png

Enlarge for clarity.

set bpSCALE=50
set bpTEXT=G0
call %PICTBAT%blockPix mos_msk_G0.png
set bpTEXT=G1
call %PICTBAT%blockPix mos_msk_G1.png
set bpTEXT=B
call %PICTBAT%blockPix mos_msk_B.png
set bpTEXT=
set bpSCALE=
mos_msk_G0_bp.png mos_msk_G1_bp.png mos_msk_B_bp.png

We separate the channels, then compose green over red, green over the result, and blue of the result. The composites are made with the masks, tiled to the full size.

"-colorspace sRGB" is for v7. If the input is grayscale, "-separate" would do nothing.

"-channel RGB" ensures we don't separate out the alpha channel, in either v6 or v7.

%IM%convert ^
  %SRC% ^
  -colorspace sRGB ^
  -channel RGB ^
  -separate ^
  -compose Over ^
  ( -clone 0,1 ^
    ( +clone ^
      -tile mos_msk_G0.png ^
      -draw "color 0,0 reset" ^
    ) ^
    -composite ^
  ) ^
  ( -clone 3,1 ^
    ( +clone ^
      -tile mos_msk_G1.png ^
      -draw "color 0,0 reset" ^
    ) ^
    -composite ^
  ) ^
  ( -clone 4,2 ^
    ( +clone ^
      -tile mos_msk_B.png ^
      -draw "color 0,0 reset" ^
    ) ^
    -composite ^
  ) ^
  -delete 0--2 ^
  mos_samp_out.png
mos_samp_out.pngjpg

The result is grayscale, but each pixel represents one of R, G0, G1 or B.

The script

The script mosaic.bat does the work in one command.

call %PICTBAT%mosaic ^
  dm_cars_demos.jpg ^
  . . . . ^
  mos_cars.png
mos_cars.pngjpg

This doesn't represent the values from a camera's sensor. To get those, we would first convert from sRGB to RGB, then divide by the colour balance numbers, eg 1.9, 1.0, 1.0, 1.4 for RGGB.

Round trips

Now we have a mosaic image, we can demosaic as shown in the Demosaicing page.

call %PICTBAT%demos ^
  mos_cars.png ^
  . . . . . ^
  mos_cars_demos.png
mos_cars_demos.pngjpg

The round trip has roughly re-created the initial image, though resolution has noticably decreased.

%IM%compare -metric RMSE ^
  dm_cars_demos.jpg ^
  mos_cars_demos.png ^
  NULL: 
3100.97 (0.0473178)

We can test the round-trip on graphical images:

%IM%convert ^
  -size 300x200 xc:gray(75%%) ^
  -fill #f40 -draw "rectangle 10,10 100,100" ^
  -fill #4f08 -draw "rectangle 80,20 180,120" ^
  -fill #000 -draw "circle 100,130 160,130" ^
  mos_ex1.png
mos_ex1.png
call %PICTBAT%mosaic ^
  mos_ex1.png ^
  . . . . ^
  mos_ex1_m.png
mos_ex1_m.png
call %PICTBAT%demos ^
  mos_ex1_m.png ^
  . . . . . ^
  mos_ex1_md.png
mos_ex1_md.png

False colours have been introduced at the sharp edges. Possible solutions include:

%IM%convert ^
  -size 200x600 gradient: -rotate 90 ^
  -distort Arc "360 -90 100" +repage ^
  -evaluate sin 50 ^
  mos_rad.png
mos_rad.png
call %PICTBAT%mosaic mos_rad.png

Mosaicing a grayscale file results in the same image.

mos_rad_mos.png
call %PICTBAT%demos %mosOUTFILE%
mos_rad_mos_dm.png

False colours have been introduced at the sharp edges in the center.

%IM%convert ^
  -size 200x600 gradient: -rotate 90 ^
  -distort Arc "360 -90 100" +repage ^
  -evaluate sin 50 ^
  -threshold 50%% ^
  mos_rad2.png
mos_rad2.png
call %PICTBAT%mosaic mos_rad2.png
mos_rad2_mos.png
call %PICTBAT%demos %mosOUTFILE%
mos_rad2_mos_dm.png

All the edges are sharp, so false colours have been introduced at all edges.

Scripts

For convenience, .bat scripts are also available in a single zip file. See Zipped BAT files.

mosaic.bat

rem From colour image %1,
rem makes mosaiced (Bayer) image, same size.
rem %2 %3 %4 and %5 are divisors for R G0 G1 and B channels.
rem %6 is optional output file.
@rem
@rem Assumes Bayer filter pattern is:
@rem   R  G0
@rem   G1 B

@if "%1"=="" findstr /B "rem @rem" %~f0 & exit /B 1

@setlocal enabledelayedexpansion

rem call echoOffSave

call %PICTBAT%setInOut %1 mos


if not "%6"=="" if not "%6"=="." set OUTFILE=%6

set WW=
for /F "usebackq" %%L ^
in (`%IM%identify -format "WW=%%w\nHH=%%h" %INFILE%`) ^
do set /A %%L
if "%WW%"=="" exit /B 1

set DIV_R=
set DIV_G0=
set DIV_G1=
set DIV_B=

if not "%2"=="" if not "%2"=="." set DIV_R=-evaluate divide %2
if not "%3"=="" if not "%3"=="." set DIV_G0=-evaluate divide %3
if not "%4"=="" if not "%4"=="." set DIV_G1=-evaluate divide %4
if not "%5"=="" if not "%5"=="." set DIV_B=-evaluate divide %5


goto skip

%IM%convert ^
  -size 2x2 xc:black ^
  -fill White -draw "point 0,0" ^
  +write mpr:SQR +delete ^
  -size %WW%x%HH% ^
  -tile-offset +0+0 tile:mpr:SQR +write msk_R.png +delete ^
  -tile-offset +1+0 tile:mpr:SQR +write msk_G0.png +delete ^
  -tile-offset +0+1 tile:mpr:SQR +write msk_G1.png +delete ^
  -tile-offset +1+1 tile:mpr:SQR +write msk_B.png ^
  NULL:

if ERRORLEVEL exit /B 1


%IM%convert xc:red xc:blue +append -write mpr:FIL +delete ^
  rose: ^
  -tile mpr:FIL -fuzz 100%% -draw "color 0,0 replace" r.png

%IM%convert xc:red xc:blue +append -write mpr:FIL +delete ^
  rose: ^
  -tile-offset +1+0 -tile mpr:FIL -fuzz 100%% -draw "color 0,0 replace" r2.png

%IM%convert xc:red xc:blue +append -write mpr:FIL +delete ^
  rose: ^
  -tile-offset +1+0 -tile mpr:FIL -fuzz 100%% -draw "color 0,0 reset" r3.png


%IM%convert ^
  -size 2x2 xc:black ^
  -fill White -draw "point 0,0" ^
  +write mpr:SQR +delete ^
  -size 30x20 xc: ^
  -tile-offset +1+0 -tile mpr:SQR ^
  -draw "color 0,0 reset" ^
  t0.png

%IM%convert ^
  -size 2x2 xc:black ^
  -fill White -draw "point 0,0" ^
  +write mpr:SQR +delete ^
  -size 30x20 xc: ^
  -tile-offset +0+1 -tile mpr:SQR ^
  -draw "color 0,0 reset" ^
  t1.png

%IM%convert ^
  -size 2x2 xc:black ^
  -fill White -draw "point 0,0" ^
  +write mpr:SQR +delete ^
  -size 30x20 xc: ^
  -tile-offset +1+1 -tile mpr:SQR ^
  -draw "color 0,0 reset" ^
  t2.png

%IM%convert ^
  -size 2x2 xc:black ^
  -fill White -draw "point 1,0" ^
  +write mpr:SQR_G0 ^
  -roll +0+1 +write mpr:SQR_B ^
  -roll -1+0 +write mpr:SQR_G1 ^
  +delete ^
  -size 30x20 xc: ^
  ( +clone ^
    -tile mpr:SQR_G0 ^
    -draw "color 0,0 reset" ^
    +write u0.png +delete ^
  ) ^
  ( +clone ^
    -tile mpr:SQR_G1 ^
    -draw "color 0,0 reset" ^
    +write u1.png +delete ^
  ) ^
  ( +clone ^
    -tile mpr:SQR_B ^
    -draw "color 0,0 reset" ^
    +write u2.png ^
  ) ^
  NULL:


%IM%convert ^
  %INFILE% ^
  -colorspace sRGB ^
  -separate ^
  +write info: ^
  ( -clone 0,1 ^
    msk_G0.png ^
    -composite ^
  ) ^
  ( -clone 3,1 ^
    msk_G1.png ^
    -composite ^
  ) ^
  ( -clone 4,2 ^
    msk_B.png ^
    -composite ^
  ) ^
  -delete 0--2 ^
  %OUTFILE%

if ERRORLEVEL 1 exit /B 1

rem goto skip2

:skip

%IM%convert ^
  -size 2x2 xc:black ^
  -fill White -draw "point 1,0" ^
  -fill None ^
  +write mpr:SQR_G0 ^
  -roll +0+1 +write mpr:SQR_B ^
  -roll -1+0 +write mpr:SQR_G1 ^
  +delete ^
  %INFILE% ^
  -colorspace sRGB ^
  -channel RGB ^
  -separate ^
  -compose Over ^
  ( -clone 0,1 ^
    ( +clone ^
      -tile mpr:SQR_G0 ^
      -draw "color 0,0 reset" ^
    ) ^
    -alpha off -composite ^
  ) ^
  ( -clone 3,1 ^
    ( +clone ^
      -tile mpr:SQR_G1 ^
      -draw "color 0,0 reset" ^
    ) ^
    -alpha off -composite ^
  ) ^
  ( -clone 4,2 ^
    ( +clone ^
      -tile mpr:SQR_B ^
      -draw "color 0,0 reset" ^
    ) ^
    -alpha off -composite ^
  ) ^
  -delete 0--2 ^
  %OUTFILE%

:skip2

if ERRORLEVEL 1 exit /B 1

call echoRestore

endlocal & set mosOUTFILE=%OUTFILE%

All images on this page were created by the commands shown, using:

%IM%convert -version
Version: ImageMagick 6.9.2-5 Q16 x64 2015-10-31 http://www.imagemagick.org
Copyright: Copyright (C) 1999-2015 ImageMagick Studio LLC
License: http://www.imagemagick.org/script/license.php
Visual C++: 180031101
Features: Cipher DPC Modules OpenMP 
Delegates (built-in): bzlib cairo freetype jng jp2 jpeg lcms lqr openexr pangocairo png ps rsvg tiff webp xml zlib

Source file for this web page is mosaic.h1. To re-create this web page, execute mosaic.bat.


This page, including the images, is my copyright. Anyone is permitted to use or adapt any of the code, scripts or images for any purpose, including commercial use.

Anyone is permitted to re-publish this page, but only for non-commercial use.

Anyone is permitted to link to this page, including for commercial use.


Page version v1.0 15-April-2016.

Page created 20-May-2016 14:59:33.

Copyright © 2016 Alan Gibson.