%matplotlib inline
from IPython.display import HTML,Image,SVG,YouTubeVideo
Object moments¶
We have seen that moments can be used to describe contours, similarily, the content of the shape can be described by this feature.
- definition The definition in the continuous domain is as follow
for a discrete domain, which is the case for image of pixels, we have
to eliminate the influence of the absolute shape position, one define the centered moments $\mu$
$$ \mu_{pq} = \sum_{x= -\infty}^{+\infty}\sum_{y=-\infty}^{+\infty} (x-\bar x)^p \; (y-\bar y)^q \; f(x,y) $$to eliminate the influence of the scale, one define $\eta$ as the normalized $\mu$
$$ \eta_{pq} = \frac{\mu_{pq}}{\mu_{00}^\gamma} $$with
$$ \gamma = \frac{p+q}{2} + 1 $$Up to here, $\eta_{pq}$ are independent to translation and scale, by are still dependent to the rotation
Hu defined invariants, called Hu's invariants, that combined $\eta_{pq}$ having the rotation invariance property,
$$ \begin{align} I_1 =\ & \eta_{20} + \eta_{02} \\ I_2 =\ & (\eta_{20} - \eta_{02})^2 + (2\eta_{11})^2 \\ I_3 =\ & (\eta_{30} - 3\eta_{12})^2 + (3\eta_{21} - \eta_{03})^2 \\ I_4 =\ & (\eta_{30} + \eta_{12})^2 + (\eta_{21} + \eta_{03})^2 \\ I_5 =\ & (\eta_{30} - 3\eta_{12}) (\eta_{30} + \eta_{12})[ (\eta_{30} + \eta_{12})^2 - 3 (\eta_{21} + \eta_{03})^2] + \\ \ & (3\eta_{21} - \eta_{03}) (\eta_{21} + \eta_{03})[ 3(\eta_{30} + \eta_{12})^2 - (\eta_{21} + \eta_{03})^2] \\ I_6 =\ & (\eta_{20} - \eta_{02})[(\eta_{30} + \eta_{12})^2 - (\eta_{21} + \eta_{03})^2] + 4\eta_{11}(\eta_{30} + \eta_{12})(\eta_{21} + \eta_{03}) \\ I_7 =\ & (3\eta_{21} - \eta_{03})(\eta_{30} + \eta_{12})[(\eta_{30} + \eta_{12})^2 - 3(\eta_{21} + \eta_{03})^2] + \\ \ & (\eta_{30} - 3\eta_{12})(\eta_{21} + \eta_{03})[3(\eta_{30} + \eta_{12})^2 - (\eta_{21} + \eta_{03})^2]. \end{align} $$High order invariants can be very sensitive to noise, due to the high order exponent in the sum.
see also:
- Moments [DIP] p514
import numpy as np
from skimage.morphology import disk, square
import matplotlib.pyplot as plt
from skimage.measure import label,regionprops
from skimage.io import imread
from scipy.spatial.distance import pdist,squareform
ima = imread('http://homepages.ulb.ac.be/~odebeir/data/alphabet.png')[:,:,0]==0
lab,nlab = label(ima,return_num=True)
# extract label features
props = regionprops(lab)
hu = []
for p in props:
hu.append(p.moments_hu)
hu = np.asarray(hu)
# normalize Hu's features
mean_hu = np.mean(hu,axis=0)
std_hu = np.std(hu,axis=0)
norm_hu = (hu-mean_hu)/std_hu
# compute pairwize distance based on normalized Hu's features
dist = squareform(pdist(norm_hu))
plt.figure(figsize=[10,10])
plt.imshow(dist,interpolation='nearest');
--------------------------------------------------------------------------- HTTPError Traceback (most recent call last) <ipython-input-2-2972e7a57a2a> in <module> 6 from scipy.spatial.distance import pdist,squareform 7 ----> 8 ima = imread('http://homepages.ulb.ac.be/~odebeir/data/alphabet.png')[:,:,0]==0 9 lab,nlab = label(ima,return_num=True) 10 ~/.conda/envs/py3/lib/python3.7/site-packages/skimage/io/_io.py in imread(fname, as_gray, plugin, **plugin_args) 45 plugin = 'tifffile' 46 ---> 47 with file_or_url_context(fname) as fname: 48 img = call_plugin('imread', fname, plugin=plugin, **plugin_args) 49 ~/.conda/envs/py3/lib/python3.7/contextlib.py in __enter__(self) 110 del self.args, self.kwds, self.func 111 try: --> 112 return next(self.gen) 113 except StopIteration: 114 raise RuntimeError("generator didn't yield") from None ~/.conda/envs/py3/lib/python3.7/site-packages/skimage/io/util.py in file_or_url_context(resource_name) 26 try: 27 with tempfile.NamedTemporaryFile(delete=False, suffix=ext) as f: ---> 28 u = urllib.request.urlopen(resource_name) 29 f.write(u.read()) 30 # f must be closed before yielding ~/.conda/envs/py3/lib/python3.7/urllib/request.py in urlopen(url, data, timeout, cafile, capath, cadefault, context) 220 else: 221 opener = _opener --> 222 return opener.open(url, data, timeout) 223 224 def install_opener(opener): ~/.conda/envs/py3/lib/python3.7/urllib/request.py in open(self, fullurl, data, timeout) 529 for processor in self.process_response.get(protocol, []): 530 meth = getattr(processor, meth_name) --> 531 response = meth(req, response) 532 533 return response ~/.conda/envs/py3/lib/python3.7/urllib/request.py in http_response(self, request, response) 639 if not (200 <= code < 300): 640 response = self.parent.error( --> 641 'http', request, response, code, msg, hdrs) 642 643 return response ~/.conda/envs/py3/lib/python3.7/urllib/request.py in error(self, proto, *args) 567 if http_err: 568 args = (dict, 'default', 'http_error_default') + orig_args --> 569 return self._call_chain(*args) 570 571 # XXX probably also want an abstract factory that knows when it makes ~/.conda/envs/py3/lib/python3.7/urllib/request.py in _call_chain(self, chain, kind, meth_name, *args) 501 for handler in handlers: 502 func = getattr(handler, meth_name) --> 503 result = func(*args) 504 if result is not None: 505 return result ~/.conda/envs/py3/lib/python3.7/urllib/request.py in http_error_default(self, req, fp, code, msg, hdrs) 647 class HTTPDefaultErrorHandler(BaseHandler): 648 def http_error_default(self, req, fp, code, msg, hdrs): --> 649 raise HTTPError(req.full_url, code, msg, hdrs, fp) 650 651 class HTTPRedirectHandler(BaseHandler): HTTPError: HTTP Error 404: Not Found
searching for nearest resembling object, using Hu's invariant features
idx = np.argsort(dist[1,:])
plt.figure()
for j,i in enumerate(idx[:16]):
bb = props[i].bbox
crop = ima[bb[0]:bb[2],bb[1]:bb[3]]
plt.subplot(4,4,j+1)
plt.imshow(crop)
--------------------------------------------------------------------------- NameError Traceback (most recent call last) <ipython-input-3-f3ee6d2664b4> in <module> ----> 1 idx = np.argsort(dist[1,:]) 2 plt.figure() 3 for j,i in enumerate(idx[:16]): 4 bb = props[i].bbox 5 crop = ima[bb[0]:bb[2],bb[1]:bb[3]] NameError: name 'dist' is not defined