2

I'm currently doing a student project which does some image processings (dilation and erosion) on greyscale pgm file. I tried to implement dilation on the image object but got weird result. I expected the image object will be larger than the original image. But I got multiple copies of the object depending the kernel size I use.

Original Picture:

Original Picture

Dilation result:

Dilation Result

This is my dilation source code

import numpy as np


def pgm_read(filename):
    """Read PGM file to a array"""
    # Performance Bottleneck: I/O system calls, parallel write/read
    try:
        with open(filename, 'r') as fp:
            lines = fp.readlines()
            header_info = lines[2].split()
            return np.array([line.strip('\n') for line in lines[4:]], dtype=np.int32).reshape(int(header_info[0]),
                                                                                              int(header_info[1]))
    except OSError:
        print("An exception occurred")


def pgm_write(img, dest, header):
    """Write numpy array to PGM file"""
    try:
        header = "P2\n# test\n" + header + "\n80\n"

        f = open(dest, "w")
        f.write(header)
        f.close()
        with open(dest, "a") as f:
            for x in range(img.shape[0]):
                for y in range(img.shape[1]):
                    f.write(str(img[x][y]) + "\n")
    except OSError:
        print("Writing exception occurred")


def dilation(img):

    rows, cols = img.shape
    dilated_img = np.zeros((rows, cols), dtype=np.int32)

    kernel = np.ones((2, 2))
    rows2, cols2 = kernel.shape

    for x in range(rows):
        for y in range(cols):
            """Search the object within the image"""
            if img[x][y] == 1:
                # Convolve with kernel
                for i in range(rows2):
                    for j in range(cols2):
                        if kernel[i][j] == 1:
                            # Object Enlargement
                            c = x + i
                            d = y + j
                            if c < rows and d < cols:
                                dilated_img[c][d] = 1

    for x in range(rows):
        for y in range(cols):
            """Give the object brightest colour for debugging purpose"""
            if dilated_img[x][y] == 1:
                dilated_img[x][y] = 80

    return dilated_img


if __name__ == '__main__':
    a = pgm_read("Axial_68.pgm")
    a = dilation(a)
    target = "Axial_68_1.pgm"
    header = "265 490"
    pgm_write(a, target, header)

Axial_68.pgm

I am very certain my file reading and writing functions work properly as I can use it to read and write other source pgm file properly.

And one thing I found very weird behaviour is I could print half pgm file like this.

Half Horizontal

using code

    for x in range(rows // 2):
        for y in range(columns):
            arr[x][y] = 80

But when I use this code and expect half vertical using code:

    for x in range(rows):
        for y in range(columns // 2):
            arr[x][y] = 80

I got this:

Half vertical

I have tried this with a few other generated pgm files and all are same result. I wonder if my dilation code has something to do with this weird behaviour.

Cris Luengo
  • 55,762
  • 10
  • 62
  • 120
Melvyn Tie
  • 38
  • 6
  • Sorry about it. I've edited my question to make it reproducible. – Melvyn Tie Feb 10 '20 at 00:27
  • Since the half horizontally working as I expected, I expected the half vertically should be working as well because there are still other values in the pgm files. I just changed the half columns value to max value and this means the rest values are still there and not affected. I have tried to use `header = "265 245"`, the result was just half of the size of the original pgm file's width and the weird white black stuff is still there. – Melvyn Tie Feb 10 '20 at 00:48
  • Tried. Same thing happened. – Melvyn Tie Feb 10 '20 at 00:53
  • Pretty weird. If I save the pgm files as P5 format. Everything works properly, but P2 format same thing happened over again. – Melvyn Tie Feb 10 '20 at 11:41

1 Answers1

2

It always helps displaying a matrix directly, rather than relying on routines that you wrote yourself to write it to file for examination. For example, adding

import matplotlib.pyplot as pp
#...
    a = pgm_read("Axial_68.pgm")
    pp.imshow(a)
    pp.show()

to your code immediately reveals that the input image is not read in correctly. Swapping the two dimensions in the reshape function call fixed it for me:

return np.array([line.strip('\n') for line in lines[4:]], dtype=np.int32).reshape(int(header_info[1]),
                                                                                  int(header_info[0]))

I highly recommend that you use a library to read and write image files. For example imageio is a good option. Matplotlib itself also reads and writes various image file formats. If you want to do image processing, get a library for that too. For example Pillow, OpenCV or DIPlib. These all also include image file reading and writing functionality.

Cris Luengo
  • 55,762
  • 10
  • 62
  • 120
  • Thank you so much! You literally save my life. I've been stuck on this issue for 3 days! But one thing I don't understand is when I use IDE to display the pgm files reading array, values distribution made sense to me and I tried my file reading method on the other pgm files. All worked fine which is why I never suspected the problem occur in the reading array. – Melvyn Tie Feb 10 '20 at 16:02
  • The reason why I decided to write the functions myself is because all image reading library for pgm is P5 format. I couldn't find any for P2 format. I will definitely check out the libraries you suggested. Anyway, thanks again for your help. Appreciate! – Melvyn Tie Feb 10 '20 at 16:04