I want to segment the image below (click for bigger image) into columns based on the natural gaps that exist in the columns. The columns should be perfectly vertical and need not be the same size, but should split each column by itself.

I have tried Hough Line Transform, Scipy Label, convolution filters, specifying manual cuts, etc. all with very limited success and nothing I would consider a "solution".

What approach should I take to segment these types of images into columns? Preferably a solution that I can code myself or exists in OpenCV or Python.

excerpt from full image

  • $\begingroup$ What exactly seems to be the problem here? Are you looking for a fully automated solution to the problem? If yes, is this a representative image? Are there other cases that might come up and would need to also be identified? $\endgroup$
    – A_A
    Nov 14, 2018 at 9:43

2 Answers 2


You may not need to delve into or . The following solution uses and :

from PIL import Image
import numpy

#define a greyscale threshold which we will use later
threshold = 230 

#open image as greyscale with PIL and convert to numpy array
with Image.open('your_image.png').convert('L') as img:
    arr_gry = numpy.array(img)

#create 1-D array of max column values
colmax = numpy.zeros(arr_gry.shape[0])
colmax = numpy.min(arr, axis=0)

#analyse the bands array and define start and end of each band
band_limits = {}
band_list = []
prev_column = 0
for i,column in enumerate(colmax):
    if column > threshold and ('start' not in band_limits):
        band_limits['start'] = i
    if column <=threshold and prev_column > threshold:
        band_limits['end'] = i
        band_limits = {}
    prev_column = column

###The following is for illustration purposes only

#convert to RGB array
arr_clr = numpy.stack([arr_gry,arr_gry,arr_gry], axis=2)

#Colour the bands and mid points
for band in band_list:
    arr_clr[:,band['start']:band['end']] = [255,0,0]
    arr_clr[:,(band['start']+band['end'])//2] = [0,0,255]

#Convert array to Image
out = Image.fromarray(arr_clr)

This produces the following imagesegments

Obviously you can use if desired to open, view and save the images. But in this example all the processing is done in so is more than capable.


Just an optimized version of Colin Dickie's solution above.

import numpy as np
import matplotlib.pyplot as plt

im = plt.imread("samples/20181102_CCPED1_120sec.png")

threshold = 0.9
colmax = np.min(im, axis=0)
col_filt = 1*(colmax > threshold) - 1*(colmax <= threshold)

im_filt = im
im_filt[:, col_filt == 1] = 0.0


enter image description here


Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.