Manual implementation bayern to RGB

2020-07-25 12:43发布

问题:

I'm trying to implement image transformation Bayern Pattern -> RGB

I uploaded this image:

Here is a snippet of my code:

import cv2
import numpy as np
from matplotlib import pyplot as plt
import math
import os
PATH = 'data/'

file_path = os.path.join(PATH, 'oldwell_mosaic.png')
img = cv2.imread(file_path, 0)
w, h = img.shape
new_image = np.zeros((w, h, 3), dtype = np.uint8)
# Green
new_image[1::2,1::2,1] = img[1::2,1::2]
new_image[::2, ::2, 1] = img[::2, ::2]

# Blue
new_image[1::2,::2,0] = img[1::2,::2]

# Red
new_image[::2, 1::2, 2] = img[::2, 1::2]

In the above example I use this pattern:

I am supposed to interpolate the missing values but the places with 'no values' are actually filled with zeros. When I perform this:

kernel = np.ones((4,4), np.float)/16
new_image[:,:,2] = cv2.filter2D(new_image[:, :, 2], -1, kernel)

I don't get the expected result as I'm using zeros in interpolation.

回答1:

I am not using python nor opencv but was curious so here low level C++ approach for this:

  1. process image by bands separately
  2. for each pixel you need intensity accumulator acc[][] and counter cnt[][]

    the need for counter can be avoided. You can use predefined counts encoded in similar manner then the mask in my code but this mean handling special cases on edges and corners of image. I chose acc,cnt for simplicity (they fit into 32bit easily so there is no point to not using it).

    The division can be done with bit-shift for speed (except on edges and corners)

  3. clear acc,cnt with zero

  4. process each pixel containing processed band

    add the band intensity to acc and increment cnt to pixel position and also to all neighbors not containing this band.

  5. after whole image processed compute pixel band value

    simply by

    pixel[y][x].band = acc[y][x]/cnt[y][x]
    

    By this you can use the same buffer for acc,cnt for next band.

My C++ implementation:

    picture pic0,pic1,pic2; // pic0 - original input image,pic1 output, pic2 temp band interpolation
    int x,y,a,b,i,j;
    const int mask[3][6][6]=    // bayern mask for eac band 3 bands and common size of 2x2 and 3x3 is 6x6
        {
        // blue
            {
            {0,0,0,0,0,0},
            {0,1,0,1,0,1},
            {0,0,0,0,0,0},
            {0,1,0,1,0,1},
            {0,0,0,0,0,0},
            {0,1,0,1,0,1},
            },
        // green
            {
            {0,1,0,1,0,1},
            {1,0,1,0,1,0},
            {0,1,0,1,0,1},
            {1,0,1,0,1,0},
            {0,1,0,1,0,1},
            {1,0,1,0,1,0},
            },
        // red
            {
            {1,0,1,0,1,0},
            {0,0,0,0,0,0},
            {1,0,1,0,1,0},
            {0,0,0,0,0,0},
            {1,0,1,0,1,0},
            {0,0,0,0,0,0},
            },
        };
    // prepare buffers
    pic1.resize(pic0.xs  ,pic0.ys  ); pic1.pf=_pf_rgba; pic1.clear(0);
    pic2.resize(pic0.xs+2,pic0.ys+2); pic2.pf=_pf_uu;   // size enlarged to avoid edge conditions statements
    // process bands
    for (b=0;b<3;b++)
        {
        pic2.clear(0);              // clear acc,cnt
        for (j=0,y=0;y<pic0.ys;y++,(j==5)?j=0:j++)
         for (i=0,x=0;x<pic0.xs;x++,(i==5)?i=0:i++)
          if (mask[b][j][i])        // process only band b pixels
            {
            a=pic0.p[y][x].db[0];   // grayscale intensity
            // add to 4 neighbors
            pic2.p[y+0][x+1].dw[0]+=a; pic2.p[y+0][x+1].dw[1]++;
            pic2.p[y+1][x+0].dw[0]+=a; pic2.p[y+1][x+0].dw[1]++;
            pic2.p[y+1][x+1].dw[0]+=a; pic2.p[y+1][x+1].dw[1]++;
            pic2.p[y+1][x+2].dw[0]+=a; pic2.p[y+1][x+2].dw[1]++;
            pic2.p[y+2][x+1].dw[0]+=a; pic2.p[y+2][x+1].dw[1]++;
            if (b==picture::_g) continue;
            // add to 8 neighbors (for r,b bands)
            pic2.p[y+0][x+0].dw[0]+=a; pic2.p[y+0][x+0].dw[1]++;
            pic2.p[y+0][x+2].dw[0]+=a; pic2.p[y+0][x+2].dw[1]++;
            pic2.p[y+2][x+0].dw[0]+=a; pic2.p[y+2][x+0].dw[1]++;
            pic2.p[y+2][x+2].dw[0]+=a; pic2.p[y+2][x+2].dw[1]++;
            }
        for (y=0;y<pic1.ys;y++) // convert to color band
         for (x=0;x<pic1.xs;x++)
          pic1.p[y][x].db[b]=pic2.p[y+1][x+1].dw[0]/pic2.p[y+1][x+1].dw[1];
        }

I use my own picture class for images so some members are:


xs,ys is size of image in pixels
p[y][x].dd is pixel at (x,y) position as 32 bit integer type
clear(color) clears entire image with color
resize(xs,ys) resizes image to new resolution
bmp is VCL encapsulated GDI Bitmap with Canvas access
pf holds actual pixel format of the image:

enum _pixel_format_enum
    {
    _pf_none=0, // undefined
    _pf_rgba,   // 32 bit RGBA
    _pf_s,      // 32 bit signed int
    _pf_u,      // 32 bit unsigned int
    _pf_ss,     // 2x16 bit signed int
    _pf_uu,     // 2x16 bit unsigned int
    _pixel_format_enum_end
    };


color and pixels are encoded like this:

union color
    {
    DWORD dd; WORD dw[2]; byte db[4];
    int i; short int ii[2];
    color(){}; color(color& a){ *this=a; }; ~color(){}; color* operator = (const color *a) { dd=a->dd; return this; }; /*color* operator = (const color &a) { ...copy... return this; };*/
    };


The bands are:

enum{
    _x=0,   // dw
    _y=1,

    _b=0,   // db
    _g=1,
    _r=2,
    _a=3,

    _v=0,   // db
    _s=1,
    _h=2,
    };

The bayern mask has 1 for pixels that has the color band included and item mask[band][j=0][i=0] represents pixel[y=0][x=0]. Finally here the result: for your input image: