Improve efficiency of Harris Corner Detector - python

I built this Harris Corner Detector which works exactly as it's expected in terms of functionality however when it comes to performance it is extremely slow. I am almost sure that it has to do with the fact that I'm accessing every pixel of the image but it might also be that I'm implementing something wrong. I've been thinking of how to optimize np array access for applying the filters but because of the nature of these filters I still can't come up with a good idea.
The method is not slow by itself as with OpenCV is basically instant for the same image.
import numpy as np
import cv2 as cv
import matplotlib.pyplot as pl
import matplotlib.cm as cm
import math
def hor_edge_strength(x, y, img_in = [], filter = []):
strength = 0
for i in range (0,3):
for j in range (0,3):
strength += img_in[x+i-1][y+j-1] * filter[i][j]
return strength
def ver_edge_strength(x, y, img_in = [], filter = []):
strength = 0
for i in range (0,3):
for j in range (0,3):
strength += img_in[x+i-1][y+j-1] * filter[i][j]
return strength
def gauss_kernels(size,sigma=1):
## returns a 2d gaussian kernel
if size<3:
size = 3
m = size/2
x, y = np.mgrid[-m:m+1, -m:m+1]
kernel = np.exp(-(x*x + y*y)/(2*sigma*sigma))
kernel_sum = kernel.sum()
if not sum==0:
kernel = kernel/kernel_sum
return kernel
sobel_h = [[-1, 0, 1], [-2, 0, 2], [-1, 0, 1]]
sobel_v = [[1, 2, 1], [0, 0, 0], [-1, -2, -1]]
img_arr = ['checker.jpg'] #Test image
for img_name in img_arr:
img = cv.imread(img_name,0)
sep = '.'
img_name = img_name.split(sep, 1)[0]
print img_name
gray_img = img.astype(float)
gx = np.zeros_like(gray_img)
gy = np.zeros_like(gray_img)
print 'Getting strengths'
for i in range(1, len(gray_img) - 1):
for j in range(1, len(gray_img[0]) - 1):
gx[i][j] = hor_edge_strength(i, j, gray_img, sobel_h)
gy[i][j] = ver_edge_strength(i, j, gray_img, sobel_v)
I_xx = gx * gx
I_xy = gx * gy
I_yy = gy * gy
gaussKernel = gauss_kernels(3,1)
W_xx = np.zeros_like(gray_img)
W_xy = np.zeros_like(gray_img)
W_yy = np.zeros_like(gray_img)
print 'Convoluting'
for i in range(1, len(gray_img) - 1):
for j in range(1, len(gray_img[0]) - 1):
W_xx[i][j] = hor_edge_strength(i, j, I_xx, gaussKernel)
W_xy[i][j] = hor_edge_strength(i, j, I_xy, gaussKernel)
W_yy[i][j] = hor_edge_strength(i, j, I_yy, gaussKernel)
print 'Calculating Harris Corner'
k = 0.06
HCResponse = np.zeros_like(gray_img)
for i in range(1, len(gray_img) - 1):
for j in range(1, len(gray_img[0]) - 1):
W = np.matrix([[W_xx[i][j],W_xy[i][j]],[W_xy[i][j],W_yy[i][j]]]) #For lap purposes, but not needed
detW = W_xx[i][j]*W_yy[i][j] - (W_xy[i][j] * W_xy[i][j])
traceW = W_xx[i][j] + W_yy[i][j]
HCResponse[i][j] = detW - k*traceW*traceW
threshold = 0.1
imageTreshold = max(HCResponse.ravel()) * threshold
HCResponseTreshold = (HCResponse >= imageTreshold) * 1
candidates = np.transpose(HCResponseTreshold.nonzero())
print 'Drawing'
x, y = gray_img.shape
image = np.empty((x, y, 3), dtype=np.uint8)
image[:, :, 0] = gray_img
image[:, :, 1] = gray_img
image[:, :, 2] = gray_img
for i in candidates:
x,y = i.ravel()
image[x][y] = [255,0,0]
pl.imshow(image)
pl.show()
pl.savefig(img_name + '_edge.jpg')
Is there any possible solution to substantially improve the performance of this edge detector?

import cv2
import numpy as np
filename = 'chess1.jpg'
img = cv2.imread(filename)
gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
gray = np.float32(gray)
dst = cv2.cornerHarris(gray,2,3,0.04)
#result is dilated for marking the corners, not important
dst = cv2.dilate(dst,None)
# Threshold for an optimal value, it may vary depending on the image.
img[dst>0.01*dst.max()]=[0,0,255]
cv2.imshow('dst',img)
if cv2.waitKey(0) & 0xff == 27:
cv2.destroyAllWindows()
for more info see this link

Related

Why is my code only working on part of my image?

I created code to equalize the luminosity values of pixels in an image so that when the image is further edited I do not have dark or light spots in my final image. However, the code seems to stop short and only equalize part of my image. Any ideas as to why the code is stopping early?
Here is my code:
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.image as mpimg
img = mpimg.imread('EXP_0159-2_8b.tif')
imgOut = img.copy()
for i in range(0, len(img[0, :])):
imgLine1 = (img[:, i] < 165) * img[:, i]
p = imgLine1.nonzero()
if len(p[0]) < 1:
imgOut[:, i] == 0
else:
imgLine2 = imgLine1[p[0]]
def curvefitting(lineFunction):
x = np.arange(0, len(lineFunction))
y = lineFunction
curve = np.polyfit(x, y, deg = 2)
a = curve[0]
b = curve[1]
c = curve[2]
curveEquation = (a*(x**2)) + (b*(x**1)) + (c)
curveCorrected = lineFunction - curveEquation + 200
return curveCorrected
imgLine1[p[0]] = curvefitting(imgLine2)
imgOut[:, i] = imgLine1
plt.imshow(imgOut, cmap = 'gray')
The for loop takes the individual columns of pixels in my image and restricts the endpoints of that column to (0, 165), so that pixels outside of that range are turned into zero and ignored by the nonzero() function. The if condition just finalizes the conversion of values outside (0, 165) to zero. Additionally, I converted the image to gray so I would not have to deal with colors and could focus only on luminosity.
This is my corrected image. The program works to average the luminosity values across the entire surface. However, you can see that it stops before reaching the end. The initial image was darker on the sides and lighter in the middle, but the file is too large to upload.
Any help is greatly appreciated.
If you are not interested in color you can convert input image to grayscale. That would simplified the matrix multiplications. The simplified version would be
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.image as mpimg
def rgb2gray(rgb):
return np.dot(rgb[...,:3], [0.2989, 0.5870, 0.1140])
def curvefitting(lineFunction):
x = np.arange(0, len(lineFunction))
y = lineFunction
curve = np.polyfit(x, y, deg = 2)
a = curve[0]
b = curve[1]
c = curve[2]
curveEquation = [(a*(x_**2)) + (b*(x_**1)) + (c) for x_ in x]
curveCorrected = lineFunction - curveEquation + 200
return curveCorrected
img = mpimg.imread('EXP_0159-2_8b.tif')
img = rgb2gray(img)
imgOut = img.copy()
for i in range(0, len(img[0, :])):
imgLine1 = (img[:, i] < 165) * img[:, i]
p = imgLine1.nonzero()
if len(p) < 1:
imgOut[:, i] == 0
else:
imgLine2 = imgLine1[p]
imgLine1[p] = curvefitting(imgLine2)
imgOut[:, i] = imgLine1
plt.imshow(imgOut, cmap = 'gray')
plt.show()

Why does my panorama stitch black images instead of actual images?

I want to stitch some images(identical resolution) into a panorama using openCV(without using the Stitcher class). I tried the algorithm described here, but instead of the desired panorama i get an image that is made up of the last image to be stitched and a large black area. I outputted am image for each iteration and the result is the same: current image + a larger black area each time.
import numpy
import cv2
# images is an array of images that i need to stitch
matcher = cv2.DescriptorMatcher_create(cv2.DescriptorMatcher_BRUTEFORCE_HAMMING)
ORB = cv2.ORB_create()
homography = 0
panorama = 0
for image in range(0, len(images) -1):
key1, desc1 = ORB.detectAndCompute(images[image], None)
key2, desc2 = ORB.detectAndCompute(images[image + 1], None)
matches = matcher.match(desc1, desc2, None)
matches = sorted(matches, key=lambda x: x.distance, reverse=True)
numGoodMatches = int(len(matches) * 0.15)
matches2 = matches[-numGoodMatches:]
points1 = numpy.zeros((len(matches2), 2), dtype=numpy.float32)
points2 = numpy.zeros((len(matches2), 2), dtype=numpy.float32)
for i, match in enumerate(matches2):
points1[i, :] = key1[match.queryIdx].pt
points2[i, :] = key2[match.trainIdx].pt
h, mask = cv2.findHomography(points2, points1, cv2.RANSAC)
if isinstance(homography, int):
homography = h
img1H, img1W = images[image].shape
img2H, img2W = images[image + 1].shape
aligned = cv2.warpPerspective(images[image + 1], h, (img1W + img2W, img2H))
stitchedImage = numpy.copy(aligned)
stitchedImage[0:img1H, 0:img2W] = images[image]
panorama = stitchedImage
else:
h *= homography
homography = h
img1H, img1W = panorama.shape
img2H, img2W = images[image + 1].shape
aligned = cv2.warpPerspective(images[image + 1], h, (img1W + img2W, img2H))
stitchedImage = numpy.copy(aligned)
stitchedImage[0:img1H, 0:img2W] = images[image + 1]
panorama = stitchedImage
Example of images i get:
The first image is correct.
The last image has the correct width (n * original width) but only one image and the rest is black area.
This
stitchedImage[0:img1H, 0:img2W] = images[image + 1]
places an image to the left top corner of "stitchedImage".
Somehow the image x offset must be calculated for each part of panorama:
stitchedImage[0:img1H, x_offset:x_offset+img2W] = images[image + 1]

Image goes black after thresholding

I am trying to extract blood network from this face image: Face image
For such task, i am using the P&M anisotropic diffusion found in this question: Anisotropic diffusion 2d images. Then i am using tophat transform followed by blackhat transform, afterwards i use a simple threshold to set to 255 all pixel that has an intensity value of 100.
The problem is that, after i use the threshold and try to open the image, whatever way i try, the image is displayed as fully black:
In short, my goal is to extract the blood vessels using P&M anisotropic diffusion with structuring element of flat disk of 5x5, then apply tophat and blackhat, respectively and a simple threshold and actually be able to view the image afterwards.
Here's my code on how i am trying it:
import cv2
import import cv2 numpy as np
import warnings
face_img=mpimg.imread('path')
def anisodiff(img, niter=1, kappa=50, gamma=0.1, step=(1., 1.), option=1):
if img.ndim == 3:
m = "Only grayscale images allowed, converting to 2D matrix"
warnings.warn(m)
img = img.mean(2)
img = img.astype('float32')
imgout = img.copy()
deltaS = np.zeros_like(imgout)
deltaE = deltaS.copy()
NS = deltaS.copy()
EW = deltaS.copy()
gS = np.ones_like(imgout)
gE = gS.copy()
for ii in range(niter):
deltaS[:-1, :] = np.diff(imgout, axis=0)
deltaE[:, :-1] = np.diff(imgout, axis=1)
if option == 1:
gS = np.exp(-(deltaS/kappa)**2.)/step[0]
gE = np.exp(-(deltaE/kappa)**2.)/step[1]
elif option == 2:
gS = 1./(1.+(deltaS/kappa)**2.)/step[0]
gE = 1./(1.+(deltaE/kappa)**2.)/step[1]
E = gE*deltaE
S = gS*deltaS
NS[:] = S
EW[:] = E
NS[1:, :] -= S[:-1, :]
EW[:, 1:] -= E[:, :-1]
imgout += gamma*(NS+EW)
return imgout
new_img = anisodiff(face_img, niter=1, kappa=20, gamma=0.1, step=(1., 1.), option=1)
filterSize =(3, 3)
kernel = cv2.getStructuringElement(cv2.MORPH_RECT,
filterSize)
input_image = new_img
first_tophat_img = cv2.morphologyEx(input_image,
cv2.MORPH_TOPHAT,
kernel)
filterSize =(3, 3)
kernel = cv2.getStructuringElement(cv2.MORPH_RECT,
filterSize)
second_tophat_img = cv2.morphologyEx(input_image,
cv2.MORPH_BLACKHAT,
kernel)
ret, thresh1 = cv2.threshold(second_tophat_img, 200, 255, cv2.THRESH_BINARY)
Even when i set the threshold to 254 for instance, the image goes black.
I executed a simple MATLAB implementation, and got a nice result.
MATLAB code:
I = imread('02_giorgos_1_f_M_30_830.tif');
I = im2double(uint8(I));
J = imdiffusefilt(I);
K = imtophat(J, ones(3));
figure;imshow(imadjust(K, stretchlim(K)));
Result:
I don't know if you know MATLAB, but I used the default arguments of imdiffusefilt (equivalent to anisodiff in your code).
Default MATLAB arguments are equivalent to:
Input image is in range [0, 1] and not [0, 255].
niter=5 (note: you used only 1 iteration and it's not enough).
kappa=0.1
gamma=0.125
MATLAB default is 8 neighbors connectivity (not 4 neighbors as used in anisodiff).
8 neighbors connectivity:
For getting same result as in MATLAB, I implemented an 8 neighbors connectivity Anisotropic diffusion (based on MATLAB source code).
Note: with 4 neighbors connectivity it's working, but result is not so nice as using 8 neighbors.
Displaying the output image:
In order to display the output image correctly, I used imadjust(K, stretchlim(K)).
The command stretches the range of the input image such that percentile 1 goes to 0, and percentile 99 goes to 1 (linear stretch).
One more thing:
Instead of using fixed threshold of 200, I used percentile 95 threshold:
t = np.percentile(first_tophat_img, 95)
ret, thresh1 = cv2.threshold(first_tophat_img, t, 255,
cv2.THRESH_BINARY)
Here is the code (uses cv2.imshow for testing):
import cv2
import numpy as np
import matplotlib.image as mpimg
import warnings
face_img = mpimg.imread('02_giorgos_1_f_M_30_830.tif')
def anisodiff8neighbors(img, niter=5, kappa=0.1, gamma=0.125):
""" See https://www.mathworks.com/help/images/ref/imdiffusefilt.html
Anisotropic diffusion filtering with 8 neighbors
Range of img is assumed to be [0, 1] (not [0, 255]).
"""
if img.ndim == 3:
m = "Only grayscale images allowed, converting to 2D matrix"
warnings.warn(m)
img = img.mean(2)
img = img.astype('float32')
imgout = img.copy()
for ii in range(niter):
# MATLAB source code is commented
#paddedImg = padarray(I, [1 1], 'replicate');
padded_img = np.pad(imgout, (1, 1), 'edge')
#diffImgNorth = paddedImg(1:end-1,2:end-1) - paddedImg(2:end,2:end-1);
#diffImgEast = paddedImg(2:end-1,2:end) - paddedImg(2:end-1,1:end-1);
#diffImgNorthWest = paddedImg(1:end-2,1:end-2) - I;
#diffImgNorthEast = paddedImg(1:end-2,3:end) - I;
#diffImgSouthWest = paddedImg(3:end,1:end-2) - I;
#diffImgSouthEast = paddedImg(3:end,3:end) - I;
diff_img_north = padded_img[0:-1, 1:-1] - padded_img[1:, 1:-1]
diff_img_east = padded_img[1:-1, 1:] - padded_img[1:-1, 0:-1]
diff_img_north_west = padded_img[0:-2, 0:-2] - imgout
diff_img_north_east = padded_img[0:-2, 2:] - imgout
diff_img_south_west = padded_img[2:, 0:-2] - imgout
diff_img_south_east = padded_img[2:, 2:] - imgout
#case 'exponential'
#conductCoeffNorth = exp(-(abs(diffImgNorth)/gradientThreshold).^2);
#conductCoeffEast = exp(-(abs(diffImgEast)/gradientThreshold).^2);
#conductCoeffNorthWest = exp(-(abs(diffImgNorthWest)/gradientThreshold).^2);
#conductCoeffNorthEast = exp(-(abs(diffImgNorthEast)/gradientThreshold).^2);
#conductCoeffSouthWest = exp(-(abs(diffImgSouthWest)/gradientThreshold).^2);
#conductCoeffSouthEast = exp(-(abs(diffImgSouthEast)/gradientThreshold).^2);
conduct_coeff_north = np.exp(-(np.abs(diff_img_north)/kappa)**2.0)
conduct_coeff_east = np.exp(-(np.abs(diff_img_east)/kappa)**2.0)
conduct_coeff_north_west = np.exp(-(np.abs(diff_img_north_west)/kappa)**2.0)
conduct_coeff_north_east = np.exp(-(np.abs(diff_img_north_east)/kappa)**2.0)
conduct_coeff_south_west = np.exp(-(np.abs(diff_img_south_west)/kappa)**2.0)
conduct_coeff_south_east = np.exp(-(np.abs(diff_img_south_east)/kappa)**2.0)
#fluxNorth = conductCoeffNorth .* diffImgNorth;
#fluxEast = conductCoeffEast .* diffImgEast;
#fluxNorthWest = conductCoeffNorthWest .* diffImgNorthWest;
#fluxNorthEast = conductCoeffNorthEast .* diffImgNorthEast;
#fluxSouthWest = conductCoeffSouthWest .* diffImgSouthWest;
#fluxSouthEast = conductCoeffSouthEast .* diffImgSouthEast;
flux_north = conduct_coeff_north * diff_img_north
flux_east = conduct_coeff_east * diff_img_east
flux_north_west = conduct_coeff_north_west * diff_img_north_west
flux_north_east = conduct_coeff_north_east * diff_img_north_east
flux_south_west = conduct_coeff_south_west * diff_img_south_west
flux_south_east = conduct_coeff_south_east * diff_img_south_east
#% Discrete PDE solution
#I = I + diffusionRate * (fluxNorth(1:end-1,:) - fluxNorth(2:end,:) + ...
# fluxEast(:,2:end) - fluxEast(:,1:end-1) + (1/(dd^2)).* fluxNorthWest + ...
# (1/(dd^2)).* fluxNorthEast + (1/(dd^2)).* fluxSouthWest + (1/(dd^2)).* fluxSouthEast);
imgout = imgout + gamma * (flux_north[0:-1,:] - flux_north[1:,:] +
flux_east[:,1:] - flux_east[:,0:-1] + 0.5*flux_north_west +
0.5*flux_north_east + 0.5*flux_south_west + 0.5*flux_south_east)
return imgout
#new_img = anisodiff(face_img, niter=1, kappa=20, gamma=0.1, step=(1., 1.), option=1)
face_img = face_img.astype(float) / 255;
#new_img = anisodiff(face_img, niter=5, kappa=0.1, gamma=0.125, step=(1., 1.), option=1)
new_img = anisodiff8neighbors(face_img, niter=5, kappa=0.1, gamma=0.125)
filterSize =(3, 3)
kernel = cv2.getStructuringElement(cv2.MORPH_RECT,
filterSize)
input_image = new_img
first_tophat_img = cv2.morphologyEx(input_image,
cv2.MORPH_TOPHAT,
kernel)
# Use percentile 95 (of image) as threshold instead of fixed threshold 200
t = np.percentile(first_tophat_img, 95)
ret, thresh1 = cv2.threshold(first_tophat_img, t, 255, cv2.THRESH_BINARY)
cv2.imshow('thresh1', thresh1)
filterSize =(3, 3)
kernel = cv2.getStructuringElement(cv2.MORPH_RECT,
filterSize)
second_tophat_img = cv2.morphologyEx(input_image,
cv2.MORPH_BLACKHAT,
kernel)
#ret, thresh1 = cv2.threshold(second_tophat_img, 200, 255, cv2.THRESH_BINARY)
# Use percentile 95 (of image) as threshold instead of fixed threshold 200
t = np.percentile(second_tophat_img, 95)
ret, thresh2 = cv2.threshold(second_tophat_img, t, 255, cv2.THRESH_BINARY)
cv2.imshow('thresh2', thresh2)
lo, hi = np.percentile(first_tophat_img, (1, 99))
first_tophat_img_stretched = (first_tophat_img.astype(float) - lo) / (hi-lo) # Apply linear "stretch" - lo goes to 0, and hi goes to 1
cv2.imshow('first_tophat_img_stretched', first_tophat_img_stretched)
cv2.waitKey()
cv2.destroyAllWindows()
Result:
thresh1:
thresh2:
first_tophat_img_stretched:

Multiple occurrences of bounding boxes around a same location

I implemented the following code, to match nodes in a plant, using as template a small cropped image.
img_rgb = cv2.imread('Exp.2 - Florestópolis, 35DAE, 2017-2018, T4, R2, P4.jpg')
img_rgb = cv2.medianBlur(img_rgb, 7)
img_gray = cv2.cvtColor(img_rgb, cv2.COLOR_BGR2GRAY)
template_image = cv2.imread('TemplateNode.jpg',0)
template_image = cv2.medianBlur(template_image, 5)
width, height = template_image.shape[::-1]
res = cv2.matchTemplate(img_gray, template_image, cv2.TM_CCOEFF_NORMED)
threshold = 0.6
locations = np.where(res >= threshold)
for position_tuple in zip(*locations[::-1]):
cv2.rectangle(img_rgb, position_tuple, (position_tuple[0] + width, position_tuple[1] + height), (0,255,0), 1)
However, it generates too many bounding boxes (tuples), around a same location, as show:
So, there is a work around to solve this issue?
Here is one possible approach. Code is unlikely an efficient one. I think k-means clustering from some package may work better. Idea is to group together locations, which are too close:
def group_locations(locations, min_radius):
x = locations[:, 0][ : , None]
dist_x = x - x.T
y = locations[:, 1][ : , None]
dist_y = y - y.T
dist = np.sqrt(dist_x**2 + dist_y**2)
np.fill_diagonal(dist, min_radius+1)
too_close = np.nonzero(dist <= min_radius)
groups = []
points = np.arange(len(locations))
i = 0
j = 0
while i < len(points):
groups.append([points[i]])
for j in range(len(too_close[0])):
if too_close[0][j] == points[i]:
groups[i].append(too_close[1][j])
points = np.delete(points, np.nonzero(points == too_close[1][j]))
i += 1
new_locations = []
for group in groups:
new_locations.append(np.mean(locations[group], axis=0))
return np.array(new_locations)
So you take your locations and group them before plotting:
locations = []
size = 600
for _ in range(50):
locations.append((random.randint(0, size), random.randint(0, size)))
locations = np.array(locations)
min_radius = 50
new_locations = group_locations(locations, min_radius)
#I run it second time as sometimes locations form chains which are longer than radius
new_locations = group_locations(new_locations, min_radius)
plt.scatter(locations[:, 0], locations[:, 1], c='blue', label='Original locations')
plt.scatter(new_locations[:, 0], new_locations[:, 1], c='red', marker='x', label='New grouped locations')
plt.legend()
plt.show()
actually tried it with image provided
img_rgb = cv2.imread('obsvu.jpg')
img_rgb = cv2.medianBlur(img_rgb, 7)
img_gray = cv2.cvtColor(img_rgb, cv2.COLOR_BGR2GRAY)
template_image = cv2.imread('template.jpg',0)
template_image = cv2.medianBlur(template_image, 5)
width, height = template_image.shape[::-1]
res = cv2.matchTemplate(img_gray, template_image, cv2.TM_CCOEFF_NORMED)
threshold = 0.6
locations = np.where(res >= threshold)
new_locations = group_locations(np.array(locations).T, 50).T
for position_tuple in zip(*new_locations.astype(int)[::-1]):
cv2.rectangle(img_rgb, position_tuple, (position_tuple[0] + width, position_tuple[1] + height), (0,255,0), 5)
Original locations: 723
New locations: 6 (yep, template selection not the best)

Maximum likelihood pixel classification in python opencv

I would like to perform pixel classification on RGB images based on input training samples of given number of classes. So I have e.g. 4 classes containing pixels (r,g,b) thus the goal is to segment the image into four phases.
I found that python opencv2 has the Expectation maximization algorithm which could do the job. But unfortunately I did not find any tutorial or material which can explain me (since I am beginner) how to work with the algorithm.
Could you please propose any kind of tutorial which can be used as starting point?
Update...another approach for the code below:
**def getsamples(img):
x, y, z = img.shape
samples = np.empty([x * y, z])
index = 0
for i in range(x):
for j in range(y):
samples[index] = img[i, j]
index += 1
return samples
def EMSegmentation(img, no_of_clusters=2):
output = img.copy()
colors = np.array([[0, 11, 111], [22, 22, 22]])
samples = getsamples(img)
#em = cv2.ml.EM_create()
em = cv2.EM(no_of_clusters)
#em.setClustersNumber(no_of_clusters)
#em.trainEM(samples)
em.train(samples)
x, y, z = img.shape
index = 0
for i in range(x):
for j in range(y):
result = em.predict(samples[index])[0][1]
#print(result)
output[i][j] = colors[result]
index = index + 1
return output
img = cv2.imread('00.jpg')
smallImg = small = cv2.resize(img, (0,0), fx=0.5, fy=0.5)
output = EMSegmentation(img)
smallOutput = cv2.resize(output, (0,0), fx=0.5, fy=0.5)
cv2.imshow('image', smallImg)
cv2.imshow('EM', smallOutput)
cv2.waitKey(0)
cv2.destroyAllWindows()**
convert C++ to python source
import cv2
import numpy as np
def getsamples(img):
x, y, z = img.shape
samples = np.empty([x * y, z])
index = 0
for i in range(x):
for j in range(y):
samples[index] = img[i, j]
index += 1
return samples
def EMSegmentation(img, no_of_clusters=2):
output = img.copy()
colors = np.array([[0, 11, 111], [22, 22, 22]])
samples = getsamples(img)
em = cv2.ml.EM_create()
em.setClustersNumber(no_of_clusters)
em.trainEM(samples)
means = em.getMeans()
covs = em.getCovs() # Known bug: https://github.com/opencv/opencv/pull/4232
x, y, z = img.shape
distance = [0] * no_of_clusters
for i in range(x):
for j in range(y):
for k in range(no_of_clusters):
diff = img[i, j] - means[k]
distance[k] = abs(np.dot(np.dot(diff, covs[k]), diff.T))
output[i][j] = colors[distance.index(max(distance))]
return output
img = cv2.imread('dinosaur.jpg')
output = EMSegmentation(img)
cv2.imshow('image', img)
cv2.imshow('EM', output)
cv2.waitKey(0)
cv2.destroyAllWindows()

Categories