Image graying and its implementation in python

Posted by aviatorisu on Fri, 28 Feb 2020 13:32:08 +0100

1, Grayscale

Definition of grayscale

In the R, G, B image model, when R=G=B (when the three color component values are the same), then the color represents a gray color, where the value of R=G=B is called gray value, in the gray image, the gray value can also be called brightness value. Gray value range 0-255

Grayscale method

For a color image, there are four commonly used methods of graying, which are the component method maximum value method average value method weighted average method.

1. component method

This method is the most simple, that is, in the R, G, B three color components, choose any color as the gray value

2. Maximum method

The method is to find out the value of each pixel's R, G, B three color components, then find the color with the largest value, and then take the maximum value as the gray value
f(x,y)=Max{R(x,y),G(x,y),B(x,y)} f(x,y)=Max\left \{ R(x,y),G(x,y),B(x,y)\right \} f(x,y)=Max{R(x,y),G(x,y),B(x,y)}

3. Average method

This method is to find the component values of R, G and B, and finally set the gray value as the average value of the three component values.
f(x,y)=R(x,y)+G(x,y)+B(x,y)3 f(x,y)=\frac{R(x,y)+G(x,y)+B(x,y)}{3} f(x,y)=3R(x,y)+G(x,y)+B(x,y)​

4. Weighted average method

Because the sensitivity of the human eye to each color is different, in which the human eye has the highest sensitivity to green and the lowest sensitivity to blue, we can use the weighted average method to calculate the gray value, and the formula is as follows

f(x,y)=aiR(i,j)+biG(i,j)+ciB(i,j)f(x,y)=a_iR(i,j)+b_iG(i,j)+c_iB(i,j)f(x,y)=ai​R(i,j)+bi​G(i,j)+ci​B(i,j)

Grayscale application scene
  1. When a computer recognizes an object through an image, the most important factor is the gradient of the image. With the gradient, we can find the edge of the object and locate the object. However, gradient calculation must use gray-scale image. Color image is very easy to be affected by light and other factors, and there are many changes in the color of similar objects, so color image is difficult to provide some key information
  2. After the image is grayed, the dimension of the matrix is reduced, so the operation speed will be greatly improved, and the gradient information can be preserved.

2, Algorithm implementation based on python

Because in the process of image graying, it is necessary to scan the image. As for the determination of the value, we can use a single function to get it, so the scanning process is independent, and the acquisition of the value is independent. We use a Values() method alone to get the gray value we need. The parameter is a list with R, G and B values

Method as a whole is very simple, just a few lines of code. Just use all kinds of formulas to calculate the gray value. All that's left is the sweep function

The following is a class for processing BMP image files. The code in the previous section can be integrated to read 8-bit pseudo color and 24 bit true color images

class BmpManager:
    def __init__(self,fileName):
        self.f_size=None
        self.f_width=None
        self.f_height=None
        self.f_ofset=None
        self.f_bitcount=None
        self.colorTab=None
        self.Img=None
    def Parse(self,fileName):
        f=open(fileName,'rb')
        file_type=str(f.read(2),encoding='utf-8')
        assert file_type=='BM',"Wrong file type"
        file_size_byte = f.read(4)  # This can be used to read the size of the file. It needs to read 4 bytes
        f.seek(f.tell() + 4)  # Skip four useless bytes in the middle
        file_ofset_byte = f.read(4)  # Offset to read bitmap data
        f.seek(f.tell() + 4)  # Skip two useless bytes
        file_wide_byte = f.read(4)  # Read width bytes
        file_height_byte = f.read(4)  # Read height bytes
        f.seek(f.tell() + 2)  ## Skip two useless bytes in the middle
        file_bitcount_byte = f.read(4)  # Get the occupation size of each pixel
        #Here is how to convert the bytes read to the specified type
        self.f_size,=struct.unpack('l',file_size_byte)
        self.f_ofset,=struct.unpack('l',file_ofset_byte)
        self.f_width,=struct.unpack('l',file_wide_byte)
        self.f_height,=struct.unpack('l',file_height_byte)
        self.f_bitcount,=struct.unpack('i',file_bitcount_byte)
        # Determine whether there is a color table
        if self.f_ofset==1078:
            self.__256Image__(fileName)#Processing pseudo color image
        else:
            self.__24BImage(fileName) #Process true color images
    def __256Image__(self,f_name):
        'Then read the color table'
        f=open(f_name,'rb')
        self.colorTab = np.array([],dtype=int)
        f.seek(54)  # Skip file and bitmap headers
        for i in range(0, 256):
            b = struct.unpack('B', f.read(1))[0]
            g = struct.unpack('B', f.read(1))[0]
            r = struct.unpack('B', f.read(1))[0]
            alpha = struct.unpack('B', f.read(1))[0]
            self.colorTab=np.append(self.colorTab,np.array([r,g,b,255]))
        self.colorTab=self.colorTab.reshape(256,4)
        'The following section is for reading BMP Bitmap data area,Store data in numpy array'
        # Offset the file pointer first
        f.seek(self.f_ofset)
        # Because the image is an 8 bit pseudo color image, one pixel takes up one byte, that is, 8 bits
        img = np.empty(shape=[self.f_height, self.f_width, 4], dtype=int)
        cout = 0
        for y in range(0, self.f_height):
            for x in range(0, self.f_width):
                cout = cout + 1
                index = struct.unpack('B', f.read(1))[0]
                img[self.f_height - y - 1, x] = self.colorTab[index]
            while cout % 4 != 0:
                f.read(1)
                cout = cout + 1
        self.Img=img
    def __24BImage(self,f_name):
        f=open(f_name,'rb')
        f.seek(self.f_ofset)
        img=np.empty(shape=[self.f_height,self.f_width,3],dtype=int)
        cout=0
        for y in range(0,self.f_height):
            for x in range(0,self.f_width):
                BYTES=f.read(3)
                x1,x2,x3=struct.unpack('BBB',BYTES)
                cout=cout+3
                img[self.f_height - y - 1, x]=np.array([x3,x2,x1])
            while cout%4!=0:
                cout=cout+1
                f.read(1)
        self.Img=img
    def getHeight(self):
        return self.f_height
    def getWidth(self):
        return self.f_width
    def getImage(self):
        return self.Img
    def getSize(self):
        return self.f_size

    def grayScale(self,method='AVG'):
        #Next, scan the image
        for y in  range(0,self.f_height):
            for x in range(0,self.f_width):
                value=self.Values(method,self.Img[y][x])
                self.Img[y][x]=np.array([value,value,value])
    def Values(self,methods,v):
        if methods=='AVG':
            return np.average(v)
        if methods=='R':
            return v[0]
        if methods=='G':
            return v[1]
        if methods=='B':
            return v[2]
        if methods=='Max':
            return np.max(v)
        if methods=='WAvg':
            return 0.3*v[0]+0.59*v[1]+0.11*v[2]

Final operation results

Original graph

Weighted average method
Published 2 original articles, praised 0, visited 84
Private letter follow

Topics: Python encoding