Tranform HSV mask into a set of points

The name of the pictureThe name of the pictureThe name of the pictureClash Royale CLAN TAG#URR8PPP



Tranform HSV mask into a set of points



I created a HSV mask from the image. The result is like the following:
enter image description here



I hope that this mask can be represented by a set of points. My original idea was to use Skimage Skeletonize to create a line and then use the sliding window to calculate the local mean for point creation.



However, skeletonize takes too long. It requires 0.4s for each frame. This is not a good idea for video processing.
enter image description here





1. this has nothing to do with HSV. 2. Vectorization is a slow process so unless you got some more info or restrictions on the scene (shapes , orientation complexity) then do not expect fast results ...
– Spektre
Aug 12 at 6:35




2 Answers
2



Do you want the points of all True elements of the mask, or do you just want a skeleton? If the former..


import skimage as ski
from skimage import io
import numpy as np
mask = ski.io.imread('./mask.png')[:,:,0]/255
mask = mask.astype('bool')

s0,s1 = mask.shape # dimensions of mask
a0,a1 = np.arange(s0),np.arange(s1) # make two 1d coordinate arrays
coords = np.array(np.meshgrid(a0,a1)).T # cartesian product into a coordinate matrix
coords = coords[mask] # mask out the points of interest



If the latter, you can get the start and end points (from left to right) of the object in the mask in a fast way with something like


start_mat = np.stack((np.roll(mask,1,axis=1),mask),-1)
start_mask = np.fromiter(map(lambda p: np.alltrue(p==np.array([False,True])),start_mat[mask]),dtype=bool)
starts = coords[start_mask]

end_mat = np.stack((np.roll(mask,-1,axis=1),mask),-1)
end_mask = np.fromiter(map(lambda p: np.alltrue(p==np.array([False,True])),end_mat[mask]),dtype=bool)
ends = coords[end_mask]



This will give you a rough outline of the object. Outline points will be missing anywhere that the slope of the figure is 0. You may have to think of a vertical difference scheme for those areas. The same idea would work with np.roll(...,axis=0). You could just concatenate the unique points from rolling over rows to the points from rolling over columns to get the full outline.


np.roll(...,axis=0)



Averaging the correct pairs to get the skeleton isn't so easy.



Here's a resultant outline. You can definitely make this faster than 0.4s:



enter image description here



Couldn't a simple For loop work?



Scan each "across" line of your bitmap looking for...



X pos where from Black meets White = new start point.


from Black


White


start point



Also in same scanned line now look for a new X-pos:
where from White meets Black = new end point.


from White


Black


end point



Either put dots at start/end points for "outline" effect,
or else put dots in "center" effect by dot.x = (end_point - start_point) / 2


dot.x = (end_point - start_point) / 2





I believe putting the dots at the center doesn't work quite like this VC. Think about what happens where the 'arm' meets the 'body' on the image provided by OP However if you can think of a way to get the skeleton from the start and end points, I showed a faster way than a for loop to get the start and end points in my answer
– kevinkayaks
Aug 23 at 19:37





Also this outline detection fails to give the points where the slope of the figure in the mask is 0. One has to difference in the y direction in those cases.
– kevinkayaks
Aug 23 at 19:44






By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.

Popular posts from this blog

Firebase Auth - with Email and Password - Check user already registered

Dynamically update html content plain JS

How to determine optimal route across keyboard