Odstranění Bayerovy mřížky ze senzoru kamery pro Raspberry Pi (a případně i jiných čipů)

Infračervený filtr z kamery pro Raspberry Pi máme vyjmutý, několik mikročoček obrazového senzoru je lehce poškrábaných, a teorii k odstranění Bayerovy masky vysvětlenou. Pojďme ji tedy odstranit prakticky.

Jak jsem již zmínil, při vyjímání IR filtru z kamery k Raspberry Pi došlo k politováníhodné situaci, kdy několik prachových zrn z rozbitého skla filtru ulpělo na obrazovém senzoru. Zdlouhavé čištění sice dokázalo nečistoty takřka beze zbytku odstranit, ale došlo k lehkému škrábnutí horní vrstvy senzoru, která obsahuje vrstvu mikročoček směrujících viditelné spektrum elektromagnetického záření skrze Bayerovu masku k fotosenzorům jednotlivých fyzických pixelů.

Oproti velikosti obrazových senzorů v kompaktních fotoaparátech i digitálních zrcadlovkách, je ten v kameře pro Raspberry Pi velmi malý. Jeho rozměry jsou 3,67 mm x 2,73 mm. Z toho pramení i nutná obezřetnost při práci a takřka nutnost být vybaven mikroskopem/lupou, pevnými nervy a citlivýma rukama.

Jak se rozebírá kamera k Raspberry Pi už máme za sebou.


Nyní přikročíme k odstranění poměrně tvrdých vrstev mikročoček a Bayerovy masky nanesených na velmi velmi tvrdé křemíkové vrstvě, kterou se nám jen tak poškodit nepodaří. Poškodit ale můžeme jemné drátky propojující elektroniku obrazového senzoru s piny kamery. Pokud je poškodíme, není prakticky možnost, jak vzniklou škodu jednoduše napravit.

Následující návod bude spíše obrazový s vyznačením času. Uplynulý čas je v minutách bez započteného občerstvení a venčení psa. Celkem nám to může trvat hodinu a půl. Já to dělal bez jakýchkoli znalostí (a i když jsem byl smířen s případným nezdarem, dával jsem si pozor, abych se neunáhlil), takže s tímto návodem by to mělo jít rychleji. Pokud chcete vidět obrázky ve větším rozlišení, otevřete si je v jiném okně. Pro přehlednost se zobrazují menší.

Čas T NULA (0) – čistý originální senzor bez známek vady

Povšimněme si tenkých drátků na spodním okraji křemíku – těch se nesmíme za žádných okolností dotknout. Na obrázku vypadají robustně, ale ve zkutečnosti je na ně bojíme jenom pohlédnout.

Poslední barevná fotografie pořízená kamerou – už dlouho bez IR filtru.

Čas T + 2 – nádech a rýpeme

Vezmeme jehlu a to senzoru začneme „kreslit.“ Aktivní plochu obrazového senzoru poznáme podle odrazů světla – duhové zabarvení s tenkou linkou okolo. Já použil ocelovou rýsovací jehlu, ale jehla na šití či injekční jehla poslouží také. Není potřeba se bát poškození senzoru, pouze drátků na spodku. Samozřejmě neryjeme velkou silou. Jde nám o to, abychom povrch senzoru narušili a mohli pokračovat s měkčím nástrojem se kterým tolik nehrozí poškození obrazového senzoru.

Čas T + 5 – vrstva mikročoček a Bayerovy masky je narušena

Na obrázku je vidět narušení horních vrstev nad křemíkem. V tuto chvíli jsem vzal do ruky dřevěné jídelní párátko a po senzoru začal „šmrdlat“/přejíždět. Není potřeba se bát, můžeme zatlačit.

Čas T + 7 – dřevěným nástrojem odstraňujeme vrstvy

Čas T + 11 – první kontrolní snímek pořízení senzorem

Vidíme místa s odstraněnými vrstvami. K pořízení takového kontrolního snímku musíme přiložit objektiv. V mém případě používám klasický s M12 závitem a proto přišroubování není tak náročné.

Čas T + 15 – stále zbývá mnoho práce

Čas T + 28

Barevné mapy mohou děsit, ale vše je v pořádku a stále pokračujeme s dřevěným nástrojem, který nožem přiřezáváme a ostříme.

Čas T + 30 – druhý kontrolní snímek

Občas vytvoříme kontrolní snímek který nám ukáže co již obrazový senzor vidí/nevidí a ověříme funkčnost elektroniky – jestli jsme neporušili drátové spoje.

Čas T + 42

Čas T + 46

Čas T + 59

Po hodině titěrné práce to vypadá, že máme skoro hotovo, ale opak je pravdou. Čeká nás práce s lupou a odstraňování mikročástic Bayerovy masky, která nám na povrchu zůstala. V rozích senzoru nám ale materiálu na odstranění zůstalo ještě poměrně hodně.

Pokud jsme ještě neměli přestávku, je ten správný čas.

Čas T + 69

Čas T + 75

Na pomoc přichází vatový tampón.

Čas T + 82

Senzor se špičkou dřevěného párátka. Stále odstraňuji nečistoty na povrchu a proces kontroluji lupou.

Čas T + 88

Opravdu jemné nečistoty nelze odstranit jinak než tenkým měděným drátkem – průměr 0,1 mm.

Čas T + 93 – hlásím konec operace

Senzor je takřka čistý, ale nevlastním absolutně bezprašně prostředí. Po předchozích minutách trápení vím, že lepší už to nebude.

Výsledek

Pokud se podíváme na výsledek, je opravdu dobrý. Snímky jsou pořízeny na Raspberry Pi ve formátu JPEG. Pro práci s RAW (JPEG s vloženým RAW) se mi na Raspberry Pi osvědčil program dcraw,  který umí RAW z JPEG extrahovat a zpracovat jako monochromatický, a následně uložit do bezztrátového TIFF (parametry -D -6 -T) s jedním kanálem, viz Odstranění Bayerovy mřížky ze senzoru kamery nebo fotoaparátu.

Soudkovitá chyba je záležitostí nevhodného objektivu.

Flat Field Frame – algoritmus optického senzoru a firmware Raspberry Pi si nedokážou poradit s celou plochou bílé barvy, proto je v JPEG zelená plocha.

„Monochromatické“ fotografie JPEG obsahují tři barevné kanály – R-G-B a senzor s firmware nedokážou vyvážit bílou barvu – to je očekávaný stav.

Pro další zpracování je nejjednodušší použít přímo na Raspberry Pi program dcraw s parametry -D -6 -T a výsledný obrázek v TIFF upravit např. v GIMPu, Adobe Photoshop, atd.

Programové zpracování

Pokud fotografujeme kamerou na Raspberry Pi, musíme provést několik kroků. Tím prvním je vlastní pořízení fotografie, následuje izolace RAW dat, konverze do monochromatického TIFF, přenos do počítače a finální úprava ve vhodném grafickém editoru.

Fotografování z CLI

Fotografovat z operačního systému Raspbian přímo na Raspberry Pi můžeme nejjednodušeji nástrojem raspistill. V každém případě musíme nechat do výsledného datového souboru nechat také RAW data.

root@linux:~# raspistill --raw -v -o image.jpg

raspistill Camera App v1.3.11

Width 2592, Height 1944, quality 85, filename image.jpg
Time delay 5000, Raw yes
Thumbnail enabled Yes, width 64, height 48, quality 35
Link to latest frame enabled  no
Full resolution preview No
Capture method : Single capture

Preview Yes, Full screen Yes
Preview window 0,0,1024,768
Opacity 255
Sharpness 0, Contrast 0, Brightness 50
Saturation 0, ISO 0, Video Stabilisation No, Exposure compensation 0
Exposure Mode 'auto', AWB Mode 'auto', Image Effect 'none'
Flicker Avoid Mode 'off'
Metering Mode 'average', Colour Effect Enabled No with U = 128, V = 128
Rotation 0, hflip No, vflip No
ROI x 0.000000, y 0.000000, w 1.000000 h 1.000000
Camera component done
Encoder component done
Starting component connection stage
Connecting camera preview port to video render.
Connecting camera stills port to encoder input port
Opening output file image.jpg
Enabling encoder output port
Starting capture -1
Finished capture -1
Closing down
Close down completed, all components disconnected, disabled and destroyed

Nebo nám podobnou práci odvede jednoduchý program napsaný v jazyku Python:

#!/usr/bin/env python

from picamera import PiCamera, Color
import time

camera = PiCamera()

camera.start_preview()
#sleep(5)

camera.resolution = (2592, 1944)
camera.framerate = 15

#camera.resolution = (1920, 1080)
#camera.framerate = 30

#camera.resolution = (1296, 730)
#camera.framerate = 49

#camera.resolution = (640, 480)
#camera.framerate = 90

#camera.rotation = 90
camera.hflip = False
camera.vflip = False

#camera.annotate_text = "Hello world!"
#camera.annotate_text_size = 50
#camera.annotate_background = Color('blue')
#camera.annotate_foreground = Color('yellow')

#camera.brightness = 70
#camera.contrast = 70

camera.image_effect = 'none'
camera.color_effects = None
#camera.color_effects = (128, 128)
#camera.image_denoise = 'off'
camera.awb_mode = 'auto'
#camera.awb_mode = 'off' # Does not work without Bayer mask

camera.exposure_mode = 'auto'
camera.exposure_compensation = 0
camera.drc_strength = 'off'
camera.flash_mode = 'off'
camera.iso = 0
#camera.shutter_speed = 1000000

camera.exif_tags['IFD0.Copyright'] = 'Copyright (c) 2018 OK3ZB'
camera.exif_tags['EXIF.UserComment'] = 'Camera No-IR/No-BayerMask test with M12 mount'

camera.capture('image.jpg', use_video_port=False, bayer=True)

camera.stop_preview()

Výsledný datový soubor můžeme ověřit nástrojem z balíčku ImageMagick:

root@dlinux:~# identify -verbose image.jpg
Image: image.jpg
  Format: JPEG (Joint Photographic Experts Group JFIF format)
  Mime type: image/jpeg
  Class: DirectClass
  Geometry: 2592x1944+0+0
  Resolution: 72x72
  Print size: 36x27
  Units: PixelsPerInch
  Type: TrueColor
  Endianess: Undefined
  Colorspace: sRGB
  Depth: 8-bit
  Channel depth:
    red: 8-bit
    green: 8-bit
    blue: 8-bit
  Channel statistics:
    Pixels: 5038848
    Red:
      min: 45 (0.176471)
      max: 255 (1)
      mean: 180.653 (0.708443)
      standard deviation: 43.8341 (0.171898)
      kurtosis: -0.182007
      skewness: -0.84205
      entropy: 0.920643
    Green:
      min: 29 (0.113725)
      max: 246 (0.964706)
      mean: 156.06 (0.612001)
      standard deviation: 42.3297 (0.165999)
      kurtosis: -0.338969
      skewness: -0.498834
      entropy: 0.936667
    Blue:
      min: 43 (0.168627)
      max: 255 (1)
      mean: 179.761 (0.704945)
      standard deviation: 43.7908 (0.171729)
      kurtosis: -0.197782
      skewness: -0.834179
      entropy: 0.920753
  Image statistics:
    Overall:
      min: 29 (0.113725)
      max: 255 (1)
      mean: 172.158 (0.675129)
      standard deviation: 43.3238 (0.169897)
      kurtosis: -0.0189363
      skewness: -0.720438
      entropy: 0.926021
  Rendering intent: Perceptual
  Gamma: 0.454545
  Chromaticity:
    red primary: (0.64,0.33)
    green primary: (0.3,0.6)
    blue primary: (0.15,0.06)
    white point: (0.3127,0.329)
  Background color: white
  Border color: srgb(223,223,223)
  Matte color: grey74
  Transparent color: black
  Interlace: None
  Intensity: Undefined
  Compose: Over
  Page geometry: 2592x1944+0+0
  Dispose: Undefined
  Iterations: 0
  Compression: JPEG
  Quality: 100
  Orientation: Undefined
  Properties:
    date:create: 2018-11-30T16:12:06+01:00
    date:modify: 2018-11-30T16:12:06+01:00
    exif:ApertureValue: 30705/10000
    exif:BrightnessValue: 777/100
    exif:ColorSpace: 1
    exif:ComponentsConfiguration: 1, 2, 3, 0
    exif:Copyright: Copyright (c) 2018 Zdenek Brichacek
    exif:DateTime: 2018:11:30 16:12:05
    exif:DateTimeDigitized: 2018:11:30 16:12:05
    exif:DateTimeOriginal: 2018:11:30 16:12:05
    exif:ExifImageLength: 1944
    exif:ExifImageWidth: 2592
    exif:ExifOffset: 240
    exif:ExifVersion: 48, 50, 50, 48
    exif:ExposureMode: 0
    exif:ExposureProgram: 3
    exif:ExposureTime: 2454/1000000
    exif:Flash: 0
    exif:FlashPixVersion: 48, 49, 48, 48
    exif:FNumber: 28984/10000
    exif:FocalLength: 35976/10000
    exif:ImageLength: 1944
    exif:ImageWidth: 2592
    exif:InteroperabilityOffset: 996
    exif:ISOSpeedRatings: 100
    exif:Make: RaspberryPi
    exif:MakerNote: 101, 118, 61, 45, 49, 32, 109, 108, 117, 120, 61, 45, 49, 32, 101, 120, 112, 61, 50, 52, 53, 52, 32, 97, 103, 61, 50, 53, 54, 32, 102, 111, 99, 117, 115, 61, 50, 53, 53, 32, 103, 97, 105, 110, 95, 114, 61, 49, 46, 49, 54, 48, 32, 103, 97, 105, 110, 95, 98, 61, 49, 46, 49, 53, 50, 32, 103, 114, 101, 101, 110, 110, 101, 115, 115, 61, 45, 53, 57, 32, 99, 99, 109, 61, 56, 52, 54, 52, 44, 45, 51, 54, 55, 52, 44, 45, 54, 56, 56, 44, 45, 49, 52, 54, 52, 44, 54, 48, 56, 56, 44, 45, 53, 50, 52, 44, 52, 52, 48, 44, 45, 51, 55, 56, 48, 44, 55, 52, 52, 54, 44, 48, 44, 48, 44, 48, 32, 109, 100, 61, 48, 32, 116, 103, 61, 57, 55, 32, 57, 55, 32, 111, 116, 104, 61, 48, 32, 48, 32, 98, 61, 48, 32, 102, 61, 57, 55, 32, 57, 55, 32, 102, 105, 61, 48, 32, 73, 83, 80, 32, 66, 117, 105, 108, 100, 32, 68, 97, 116, 101, 58, 32, 78, 111, 118, 32, 32, 52, 32, 50, 48, 49, 56, 44, 32, 49, 54, 58, 51, 52, 58, 49, 57, 32, 86, 67, 95, 66, 85, 73, 76, 68, 95, 73, 68, 95, 86, 69, 82, 83, 73, 79, 78, 58, 32, 101, 100, 53, 98, 97, 102, 57, 53, 50, 48, 97, 51, 99, 52, 99, 97, 56, 50, 98, 97, 51, 56, 53, 57, 52, 98, 56, 57, 56, 102, 48, 99, 48, 52, 52, 54, 100, 97, 54, 54, 32, 40, 99, 108, 101, 97, 110, 41, 32, 86, 67, 95, 66, 85, 73, 76, 68, 95, 73, 68, 95, 85, 83, 69, 82, 58, 32, 100, 99, 52, 32, 86, 67, 95, 66, 85, 73, 76, 68, 95, 73, 68, 95, 66, 82, 65, 78, 67, 72, 58, 32, 109, 97, 115, 116, 101, 114, 32
    exif:MaxApertureValue: 30705/10000
    exif:MeteringMode: 2
    exif:Model: RP_ov5647
    exif:ResolutionUnit: 2
    exif:ShutterSpeedValue: 8670650/1000000
    exif:thumbnail:Compression: 6
    exif:thumbnail:ImageLength: 48
    exif:thumbnail:ImageWidth: 64
    exif:thumbnail:InteroperabilityIndex: R98
    exif:thumbnail:JPEGInterchangeFormat: 1132
    exif:thumbnail:JPEGInterchangeFormatLength: 24576
    exif:thumbnail:ResolutionUnit: 2
    exif:thumbnail:XResolution: 72/1
    exif:thumbnail:YResolution: 72/1
    exif:UserComment: 67, 97, 109, 101, 114, 97, 32, 78, 111, 73, 82, 32, 116, 101, 115, 116, 32, 119, 105, 116, 104, 32, 77, 49, 50, 32, 109, 111, 117, 110, 116
    exif:WhiteBalance: 0
    exif:XResolution: 72/1
    exif:YCbCrPositioning: 1
    exif:YResolution: 72/1
    jpeg:colorspace: 2
    jpeg:sampling-factor: 2x2,1x1,1x1
    signature: 4fda2480948d5a90dc5d1cd3c26602d58621fdba17e0545f4f1a75ab3766f8c3
  Profiles:
    Profile-exif: 25714 bytes
  Artifacts:
    filename: image.jpg
    verbose: true
  Tainted: False
  Filesize: 8.667MB
  Number pixels: 5.039M
  Pixels per second: 2.571MB
  User time: 1.910u
  Elapsed time: 0:02.959
  Version: ImageMagick 6.9.7-4 Q16 arm 20170114 http://www.imagemagick.org

Dcraw

Program dcraw provede izolaci RAW z JPEG a konverzi do monochromatického TIFF.

root@linux:~# dcraw -T -D -6 -c -v image.jpg > image.tiff
Loading OmniVision RP_ov5647 image from image.jpg ...
Building histograms...
Writing data to standard output ...

Ověření formátu:

root@linux:~# identify -verbose image.tiff
Image: image.tiff
  Format: TIFF (Tagged Image File Format)
  Mime type: image/tiff
  Class: DirectClass
  Geometry: 2592x1944+0+0
  Resolution: 300x300
  Print size: 8.64x6.48
  Units: PixelsPerInch
  Type: Grayscale
  Base type: Grayscale
  Endianess: LSB
  Colorspace: Gray
  Depth: 16-bit
  Channel depth:
    gray: 16-bit
  Channel statistics:
    Pixels: 5038848
    Gray:
      min: 0 (0)
      max: 31827 (0.485649)
      mean: 13913.5 (0.212306)
      standard deviation: 1798.08 (0.027437)
      kurtosis: 6.69876
      skewness: -0.730343
      entropy: 0.576048
  Colors: 59
  Histogram:
      6000: (    0,    0,    0) #000000000000 gray(0)
       871: ( 1152, 1152, 1152) #048004800480 gray(2%)
      1065: ( 2304, 2304, 2304) #090009000900 gray(4%)
      1458: ( 3456, 3456, 3456) #0D800D800D80 gray(5%)
      1922: ( 4608, 4608, 4608) #120012001200 gray(7%)
      2659: ( 5750, 5750, 5750) #167616761676 gray(9%)
      3828: ( 6798, 6798, 6798) #1A8E1A8E1A8E gray(10%)
      6297: ( 7754, 7754, 7754) #1E4A1E4A1E4A gray(12%)
     15014: ( 8637, 8637, 8637) #21BD21BD21BD gray(13%)
     35360: ( 9462, 9462, 9462) #24F624F624F6 gray(14%)
     78397: (10237,10237,10237) #27FD27FD27FD gray(16%)
    157920: (10971,10971,10971) #2ADB2ADB2ADB gray(17%)
    275899: (11669,11669,11669) #2D952D952D95 gray(18%)
    415519: (12335,12335,12335) #302F302F302F gray(19%)
    595895: (12974,12974,12974) #32AE32AE32AE gray(20%)
    773997: (13589,13589,13589) #351535153515 gray(21%)
    893384: (14181,14181,14181) #376537653765 gray(22%)
    796012: (14753,14753,14753) #39A139A139A1 gray(23%)
       427: (15307,15307,15307) #3BCB3BCB3BCB gray(23%)
    497592: (15844,15844,15844) #3DE43DE43DE4 gray(24%)
    267424: (16366,16366,16366) #3FEE3FEE3FEE gray(25%)
    114647: (16874,16874,16874) #41EA41EA41EA gray(26%)
     40569: (17369,17369,17369) #43D943D943D9 gray(27%)
     18019: (17851,17851,17851) #45BB45BB45BB gray(27%)
     10150: (18322,18322,18322) #479247924792 gray(28%)
      7468: (18783,18783,18783) #495F495F495F gray(29%)
      4889: (19233,19233,19233) #4B214B214B21 gray(29%)
      3370: (19674,19674,19674) #4CDA4CDA4CDA gray(30%)
      2456: (20106,20106,20106) #4E8A4E8A4E8A gray(31%)
      1841: (20529,20529,20529) #503150315031 gray(31%)
      1401: (20945,20945,20945) #51D151D151D1 gray(32%)
      1090: (21353,21353,21353) #536953695369 gray(33%)
       956: (21754,21754,21754) #54FA54FA54FA gray(33%)
       846: (22148,22148,22148) #568456845684 gray(34%)
       785: (22536,22536,22536) #580858085808 gray(34%)
       648: (22917,22917,22917) #598559855985 gray(35%)
       572: (23292,23292,23292) #5AFC5AFC5AFC gray(36%)
       542: (24026,24026,24026) #5DDA5DDA5DDA gray(37%)
       515: (24385,24385,24385) #5F415F415F41 gray(37%)
       272: (24739,24739,24739) #60A360A360A3 gray(38%)
       245: (25089,25089,25089) #620162016201 gray(38%)
       257: (25433,25433,25433) #635963596359 gray(39%)
       184: (25773,25773,25773) #64AD64AD64AD gray(39%)
        39: (26109,26109,26109) #65FD65FD65FD gray(40%)
        28: (26440,26440,26440) #674867486748 gray(40%)
        37: (26768,26768,26768) #689068906890 gray(41%)
        38: (27091,27091,27091) #69D369D369D3 gray(41%)
        12: (27411,27411,27411) #6B136B136B13 gray(42%)
         4: (27727,27727,27727) #6C4F6C4F6C4F gray(42%)
         8: (28040,28040,28040) #6D886D886D88 gray(43%)
         9: (28349,28349,28349) #6EBD6EBD6EBD gray(43%)
         1: (28655,28655,28655) #6FEF6FEF6FEF gray(44%)
         2: (28958,28958,28958) #711E711E711E gray(44%)
         1: (29257,29257,29257) #724972497249 gray(45%)
         1: (29848,29848,29848) #749874987498 gray(46%)
         3: (30138,30138,30138) #75BA75BA75BA gray(46%)
         1: (30426,30426,30426) #76DA76DA76DA gray(46%)
         1: (30711,30711,30711) #77F777F777F7 gray(47%)
         1: (31827,31827,31827) #7C537C537C53 gray(49%)
  Rendering intent: Undefined
  Gamma: 0.454545
  Background color: gray(255)
  Border color: gray(223)
  Matte color: gray(189)
  Transparent color: gray(0)
  Interlace: None
  Intensity: Undefined
  Compose: Over
  Page geometry: 2592x1944+0+0
  Dispose: Undefined
  Iterations: 0
  Compression: None
  Orientation: TopLeft
  Properties:
    comment:
    date:create: 2018-12-01T21:48:22+01:00
    date:modify: 2018-12-01T21:48:22+01:00
    exif:ExposureTime: 0.12499
    exif:FNumber: 2.89839
    exif:FocalLength: 3.5976
    exif:ISOSpeedRatings: 640
    signature: d4a66c4c9fa3723cf94b71ef0378481ff043f71b8a68d2a73ff43a9e094bcb4a
    tiff:alpha: unspecified
    tiff:artist:
    tiff:endian: lsb
    tiff:make: OmniVision
    tiff:model: RP_ov5647
    tiff:photometric: min-is-black
    tiff:rows-per-strip: 1
    tiff:software: dcraw v9.27
    tiff:timestamp: 2018:12:01 21:23:50
  Artifacts:
    filename: image.tiff
    verbose: true
  Tainted: False
  Filesize: 10.08MB
  Number pixels: 5.039M
  Pixels per second: 9.69MB
  User time: 0.270u
  Elapsed time: 0:01.520
  Version: ImageMagick 6.9.7-4 Q16 arm 20170114 http://www.imagemagick.org

Můžeme také použít aplikaci darktable:

Závěr

A obdobně to jde s obrazovými senzory ve fotoaparátech, které Bayerovu masku používají.

1 komentář u „Odstranění Bayerovy mřížky ze senzoru kamery pro Raspberry Pi (a případně i jiných čipů)

  1. Pingback: Odstranění Bayerovy mřížky ze senzoru kamery nebo fotoaparátu | brichacek.net

Leave a Reply