spyderB
spyderB

Reputation: 69

how to vertically segment an image?

I have images like this:

Input image

where all objects are connected through a horizontal line. all the symbols have different widths so can't extract all shapes using a fixed width or splitting points like when we split an array.

In this image, there are 4 symbols but in some other cases it can be more or less than 4 so here also I can't perform something like "4 symbols so divide the input image width vertically into 4 different widths. so I don't know how to extract whatever symbols the image might have efficiently like this output I want

the output I want .

Can you guys help me with this?

Image
to
output

Upvotes: 0

Views: 317

Answers (2)

Salvatore Daniele Bianco
Salvatore Daniele Bianco

Reputation: 2701

import urllib.request
from PIL import Image
from scipy import signal
import numpy as np
from matplotlib import pyplot as plt

urllib.request.urlretrieve(
  'https://i.sstatic.net/iMKIP.jpg',
   "img.png")
img = Image.open("img.png")
img.show()

enter image description here

arr = (np.array(img)<(255)/2) #I'm considering black parts as filled
plt.imshow(arr)

enter image description here

plt.subplot(211)
plt.imshow(arr, aspect="auto")
plt.subplot(212)
plt.plot(arr.sum(axis=0))
plt.xlim(0,arr.shape[1])

enter image description here

Then, in order to find local min:

x_lines = signal.find_peaks(-arr.sum(axis=0))[0]

plt.imshow(arr, aspect="auto")
plt.vlines(x_lines, 0, arr.shape[0], color="r")

enter image description here

Finally if we consider a threshold (for example 50 filled pixel in columns):

threshold = 50

x_lines = signal.find_peaks(-arr.sum(axis=0))[0]
x_lines = x_lines[arr.sum(axis=0)[x_lines]<threshold]

plt.imshow(arr, aspect="auto")
plt.vlines(x_lines, 0, arr.shape[0], color="r")

enter image description here

Edit:

To split picture you need

for i, x in enumerate(x_lines):
    if i==0:
        plt.imshow(arr[:,:x_lines[i]], cmap="Greys")
        plt.savefig("fig%i"%i)
        plt.show()
    else:
        plt.imshow(arr[:,x_lines[i-1]:x_lines[i]], cmap="Greys")
        plt.savefig("fig%i"%i)
        plt.show()
        
plt.imshow(arr[:,x_lines[i]:], cmap="Greys")
plt.savefig("fig%i"%(i+1))
plt.show()

Upvotes: 1

Shai
Shai

Reputation: 114876

Let me give it to you in . The code can be easily generalized to python.

% read the image and binarize it
img = imread('https://i.sstatic.net/iMKIP.jpg') > 128;
% compute the sum of black pixels, per column
vs = sum(1 - img, 1); 
% compute the minimal number of black pixels (ignoring the completely white boundaries)
% this will tell you at which columns you may "cut" the image
thr = min(vs(vs>0));
% find the indices of the columns that do not contain any "object"
sep = find(vs <= the);
% find where objects starts (col indices)
loc = diff(sep) > 1;
% select the column indices at the middle, between objects
col = round(0.5 * (sep(loc(1:end-1)+1) + sep(loc(2:end))));

% visualize the result
imshow(img);
hold on;  
plot([col;col], [0*col;size(img,1)*ones(1,numel(col))], 'r', 'LineWidth', 2);

This is the output:
enter image description here

with

col =

   130   243   351

Upvotes: 2

Related Questions