Python openCV: kmeans example not working - python

I am working my way through the openCV examples and sometimes the examples won't run. In many cases I just have to make small changes and it works then. In this case I found no solution so far. If I run the following code I get an error on the kmeans line. I checked the data types and it seems everything is alright. Anyone an idea what is going wrong? Thanks!
Code example from https://github.com/Itseez/opencv:
'''
Keyboard shortcuts:
ESC - exit
space - generate new distribution
'''
import numpy as np
import cv2
from gaussian_mix import make_gaussians
if __name__ == '__main__':
cluster_n = 5
img_size = 512
print __doc__
# generating bright palette
colors = np.zeros((1, cluster_n, 3), np.uint8)
colors[0,:] = 255
colors[0,:,0] = np.arange(0, 180, 180.0/cluster_n)
colors = cv2.cvtColor(colors, cv2.COLOR_HSV2BGR)[0]
while True:
print 'sampling distributions...'
points, _ = make_gaussians(cluster_n, img_size)
term_crit = (cv2.TERM_CRITERIA_EPS, 30, 0.1)
ret, labels, centers = cv2.kmeans(points, cluster_n, None, term_crit, 10, 0)
img = np.zeros((img_size, img_size, 3), np.uint8)
for (x, y), label in zip(np.int32(points), labels.ravel()):
c = map(int, colors[label])
cv2.circle(img, (x, y), 1, c, -1)
cv2.imshow('gaussian mixture', img)
ch = 0xFF & cv2.waitKey(0)
if ch == 27:
break
cv2.destroyAllWindows()
Error Message:
TypeError: an integer is required

I was using the example from the 3.x openCV version while I am running on 2.4.8. The syntax is different in 2.x:
ret, labels, centers = cv2.kmeans(points, cluster_n, term_crit, 10, 0)

Related

Is working except it isnt opening my camera to get my face cords

import cv2
import mediapipe as mp
import pyautogui as py
cam = cv2.VideoCapture(0)
face_mesh = mp.solutions.face_mesh.FaceMesh(refine_landmarks=True)
while True:
_, frame = cam.read()
frame = cv2.flip(frame, 1)
'''frameRGB = cv2.cvtColor(frame, cv2.COLOR_RGB2BGR)'''
output = face_mesh.process(frameRGB)
face_landmark = output.multi_face_landmarks
frame_w, frame_h, _ = frame.shape
'''if face_landmark:
landmarks = face_landmark[0].landmark
for landmark in enumerate(landmarks[474:478]):
x = int(landmark.x * frame_w)
y = int(landmark.y * frame_h)
cv2.circle(frame, (x, y), 3, (0, 255, 0))
if id == 1:
py.moveTo(x, y)'''
print(x, y)
cv2.imshow('Lazy mouse', frame)
cv2.waitKey(1)
it's printing where my head is for x, y, isnt showing me a camera with my face I believe it has to do with the frame or with the RGB I tried debugging but no luck, highlighted where I believe are the problems
enumerate() is a Python built-in function that returns a sequence of tuples.
Instead of
for landmark in enumerate(landmarks[474:478]): # wrong
you should use
for landmark in landmarks[474:478]:
or
for (index, landmark) in enumerate(landmarks[474:478]):
index is the index into the sublist/slice, so you will get indices 0,1,2,3

error: (-5:Bad argument) Wrong shapes for given matrices. Was size(src) = (1,41216), size(W) = (10304,100). in function 'cv::LDA::subspaceProject'

I get the error below when running the following code:
import os
import cv2 as cv
import numpy as np
import training_dataset_Eigenfaces as train
def FaceRecognition(path):
#Load the trained data
x,y,names = train.LoadImages(path)
cv2.face.EigenFaceRecognizer_create()
model = cv.face.EigenFaceRecognizer_create()
model.train(x,y)
#Turn on the camera
#Create a cascade classifier
while(True):
#Read a frame from camera
ret,frame = camera.read()
#Determine whether the image has been read successfully
if ret:
#There is importce
#Convert to grayscale
gray_img = cv.cvtColor(frame,cv.COLOR_BGR2BGRA)
# Face detection
face = face_detector.detectMultiScale(gray_img, scaleFactor=1.3, minNeighbors=5, minSize=(70, 70))
for x,y,w,h in face:
#Draw a rectangle in the original image
frame = cv.rectangle(frame,(x,y),(x+w,y+h),(0,255,0),2)
roi_gray = gray_img[y:y + h, x:x + w]
#Convert the image to a size suitable for recognition
roi_gray = cv.resize(roi_gray, (92, 112), interpolation=cv.INTER_LINEAR)
params = model.predict(roi_gray) # error comes here
print("successful!")
#Displays the name above the matrix
cv.putText(frame, names[params[0]], (x, y - 20), cv.FONT_HERSHEY_SIMPLEX, 1, 255, 2)
cv.imshow('Dynamic',frame)
#exit
the error that pops up is:
File "D:\opencv\python\Face Recognition\face-recognition-Eigenfaces.py", line 54, in FaceRecognition
params = model.predict(roi_gray)
cv2.error: OpenCV(4.6.0) D:\a\opencv-python\opencv-python\opencv\modules\core\src\lda.cpp:183: error: (-5:Bad argument) Wrong shapes for given matrices. Was size(src) = (1,41216), size(W) = (10304,100). in function 'cv::LDA::subspaceProject'
In this program, the error tells me that the matrix is not the right size, but what is the wrong size? Interpolation
roi_gray = cv.resize(roi_gray, (92, 112), Interpolation)?The purpose of this statement is to reduce the size of the image to be processed. So may I ask how to modify my program? Thank you for your answer.

How to simulate mouse clicks and dragging using co-ordinates from opencv object tracking (Python)

I'm working on a project which uses openCV to detect a blue LED and obtain its x and y co-ords. So far, i have everything working however i can't seem to find any successful way of using the co-ordinates to move the cursor in the same way you can with a physical mouse.
I have tried using the python mouse module and pynput but they both have the same issue which is that the "press" feature is very inconsistent in how it works.
What i want to be able to do is for the LED to always be detected as a single click unless it is held in which case it should drag.
The problem is, dragging only works on some windows like file explorer and doesnt work on VScode or Chrome. Also i cant draw smooth lines using the press function as it only draws straight lines.
The only way i can think of doing something like this would be to draw small straight lines in regular intervals in order to form a smooth line but i'm unsure of how something like this would be done
Maybe there is a module that already does this but i cant seem to find anything on the subject. Most questions asked here are about automating the mouse events but thats not what im after.
The code i have so far is as follow:
from cv2 import warpPerspective
from LScalibrate import warpImage
import cv2
from ast import literal_eval
import numpy as np
import mouse
def start(root, pointsstr, maskparamsmalformed, width, height):
points = literal_eval(pointsstr)
maskparamsstr = ''.join([letter for letter in maskparamsmalformed if letter not in("array()")])
maskparams = literal_eval(maskparamsstr)
lower, upper = np.array(maskparams[0]), np.array(maskparams[1])
root.withdraw()
cap = cv2.VideoCapture(0)
cap.set(15, 3) # may have to change the 2nd arg. Only supported for some cameras. Testing with droidcam therefore cannot use this myself
mat = warpImage(cap, points)
while True:
check, frame = cap.read()
if not check:
break
frame = warpPerspective(frame, mat, (1000, 1000))
hsvimg = cv2.cvtColor(frame, cv2.COLOR_BGR2HSV)
maskedimg = cv2.inRange(hsvimg, lower, upper)
image = cv2.bitwise_and(frame, frame, mask=maskedimg)
contours, rel = cv2.findContours(maskedimg, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
pts = None
contourpts = []
if len(contours) != 0:
for contour in contours:
if cv2.contourArea(contour) > 10:
x, y, w, h = cv2.boundingRect(contour)
x = (x+(x+w))//2
y = (y+(y+h))//2
pts = (x, y)
contourpts.append(pts)
check = set(contourpts)
if len(check) > 1:
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
gray = cv2.GaussianBlur(gray, (5,5), 0)
minv, maxv, minl, maxl = cv2.minMaxLoc(gray)
pts = maxl
if pts is not None:
controlCursor(pts, width, height)
cv2.circle(frame, pts, 3, (0, 0, 255), -1)
else:
mouse.release("left")
cv2.imshow("win", frame)
if cv2.waitKey(1) & 0xFF == 27:
break
cap.release()
cv2.destroyAllWindows()
root.deiconify()
def minContour(contours):
return sorted(contours, key=cv2.contourArea, reverse=False)[0]
def controlCursor(pos, w, h):
print(pos)
print(w, h)
x = (pos[0]/1000)*w
y = (pos[1]/1000)*h
print(x, y)
mouse.move(x, y, True)
mouse.press("left")
I have included a video showing how it's currently working and all the program code if needed:
Video: https://youtu.be/Q9tOIyy_tsE
Github (all code): https://github.com/ImaadNisar/Lightscreen-Touchscreen-Detection
Thanks!

Correcting rough edges

There's an image which has been extracted from another image clicked from a certain height(approx. 130ft). Now when this smaller image is extracted it contains an object, which actually has very regular and a smooth shape, has got very rough edges. Now I want to detect the no. of corners, the object has(without using contours). But due to these rough edges the no. of corners detected increases enormously.
Here are the sample images:
How can I make the edges straight?
I think what you're looking for is a simple edge smoothening algorithm. I implemented one for you. It doesn't save the colorful sign inside the outer shape though - if that's important too - since you haven't mentioned that in the question - you'll have to figure that part on your own. The result:
I've implemented track bars so you can play with the values of smoothening however it suits you. Press "c" to confirm the values you have chosen.
import cv2
import numpy as np
def empty_function(*arg):
pass
def SmootherEdgesTrackbar(img, win_name):
trackbar_name = win_name + "Trackbar"
cv2.namedWindow(win_name, cv2.WINDOW_NORMAL)
cv2.resizeWindow(win_name, 1000, 500)
cv2.createTrackbar("first_blur", win_name, 3, 255, empty_function)
cv2.createTrackbar("second_blur", win_name, 3, 255, empty_function)
cv2.createTrackbar("threshold", win_name, 0, 255, empty_function)
while True:
first_blur_pos = cv2.getTrackbarPos("first_blur", win_name)
second_blur_pos = cv2.getTrackbarPos("second_blur", win_name)
thresh_pos = cv2.getTrackbarPos("threshold", win_name)
if first_blur_pos < 3:
first_blur_pos = 3
if second_blur_pos < 3:
second_blur_pos = 3
img_res = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
img_res = smoother_edges(img_res, (first_blur_pos * 2 + 1, first_blur_pos * 2 + 1),
(second_blur_pos * 2 + 1, second_blur_pos * 2 + 1))
_, img_res = cv2.threshold(img_res, thresh_pos, 255, 0)
cv2.imshow(win_name, img_res)
key = cv2.waitKey(1) & 0xFF
if key == ord("c"):
break
cv2.destroyAllWindows()
return img_res
def unsharp_mask(img, blur_size, imgWeight, gaussianWeight):
gaussian = cv2.GaussianBlur(img, blur_size, 0)
return cv2.addWeighted(img, imgWeight, gaussian, gaussianWeight, 0)
def smoother_edges(img, first_blur_size, second_blur_size=(5, 5),
imgWeight=1.5, gaussianWeight=-0.5):
# blur the image before unsharp masking
img = cv2.GaussianBlur(img, first_blur_size, 0)
# perform unsharp masking
return unsharp_mask(img, second_blur_size, imgWeight, gaussianWeight)
# read the image
img = cv2.imread("sample.jpg")
# smoothen edges
img = SmootherEdgesTrackbar(img, "Smoother Edges Trackbar")
# show and save image
cv2.imshow("img", img)
cv2.imwrite("result.png", img)
cv2.waitKey(0)
EDIT:
After you figure out what values suit you, just delete the track bar function and perform the steps with fixed values. The algorithm goes like this:
convert to gray
blur
unsharp mask
threshold
2 middle steps are combined in smoother_edges() function.

Python OpenCV: Conversion from float to int for using cv2.line()

I'm working on the optical flow tutorial of openCV using Python 2.7 with OpenCV 3.1.0 and have a question concerning the use of cv2.line(). Here is the original code with the highlighted part of interest:
import numpy as np
import cv2
cap = cv2.VideoCapture('slow.flv')
# params for ShiTomasi corner detection
feature_params = dict( maxCorners = 100,
qualityLevel = 0.3,
minDistance = 7,
blockSize = 7 )
# Parameters for lucas kanade optical flow
lk_params = dict( winSize = (15,15),
maxLevel = 2,
criteria = (cv2.TERM_CRITERIA_EPS | cv2.TERM_CRITERIA_COUNT, 10, 0.03))
# Create some random colors
color = np.random.randint(0,255,(100,3))
# Take first frame and find corners in it
ret, old_frame = cap.read()
old_gray = cv2.cvtColor(old_frame, cv2.COLOR_BGR2GRAY)
p0 = cv2.goodFeaturesToTrack(old_gray, mask = None, **feature_params)
# Create a mask image for drawing purposes
mask = np.zeros_like(old_frame)
while(1):
ret,frame = cap.read()
frame_gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
# calculate optical flow
p1, st, err = cv2.calcOpticalFlowPyrLK(old_gray, frame_gray, p0, None, **lk_params)
# Select good points
good_new = p1[st==1]
good_old = p0[st==1]
################## IMPORTANT ##################
# draw the tracks
for i,(new,old) in enumerate(zip(good_new,good_old)):
a,b = new.ravel()
c,d = old.ravel()
mask = cv2.line(mask, (a,b),(c,d), color[i].tolist(), 2)
frame = cv2.circle(frame,(a,b),5,color[i].tolist(),-1)
################## IMPORTANT ##################
########### START insert code below ###########
# Mean-vector of camera movement
############ END insert code below ############
img = cv2.add(frame,mask)
cv2.imshow('frame',img)
k = cv2.waitKey(30) & 0xff
if k == 27:
break
# Now update the previous frame and previous points
old_gray = frame_gray.copy()
p0 = good_new.reshape(-1,1,2)
cv2.destroyAllWindows()
cap.release()
In my workspace the variables a, b, c and d are shown as array scalar float32. So I would assume, that they need to be converted to tuples of int in order to execute cv2.line() or cv2.circle().
When I try to add code using cv2.line() I have to use a conversion to int (see below), otherwise I receive a very clear message: TypeError: integer argument expected, got float
###################### START added code
ofvec = p1 - p0
ofvec = np.mean(ofvec, 1) # Collapse the first dimension
ofvec_cam = np.mean(ofvec,0) # mean of camera movement
height, width = old_frame.shape[:2]
x0 = np.int(width/2)
y0 = np.int(height/2)
pt_center = (x0, y0)
x = np.int( x0 - ofvec_cam[0].tolist() )
y = np.int( y0 - ofvec_cam[1].tolist() )
pt_ofvec_cam = (x, y)
frame = cv2.line(frame, pt_center, pt_ofvec_cam, [0, 0, 255], 2)
###################### END added code
Can anyone explain this difference to me? Thanks in advance and have a nice day!
AMTQ
It seems that cv2.line() treats differently two types of floats: "standard" Python floats and numpy floats. See the minimum working example using Python 2.7 with OpenCV 3.1.0:
import numpy as np, cv2
mask = np.zeros([10, 20, 3], dtype=np.uint8)
color = [0, 0, 0]
# Using Numpy
a = np.float32(12.34)
mask = cv2.line(mask, (a,a), (a,a), color)
# Using standard Python data type
b = 12.34
mask = cv2.line(mask, (b,b), (b,b), color)
In case a the command executes without a hitch, in case b we find the above mentioned error:
in <module> mask = cv2.line(mask, (b,b), (b,b), color)
TypeError: integer argument expected, got float`
Concerning the initial question I confirm that in the OpenCV tutorial the variables a, b, c and d are all numpy-floats whereas in the added code the variables x and y are standard Python floats before they are converted to numpy-ints by np.int().
Remarks
Both data types provide a method__int__() which returns the int-value of the float (see also difference between native int type and the numpy int types).
The only reference to speak of that I have found is this note concerning the method fromarray in the documentation of OpenCV 2.4.13:
Note In the new Python wrappers (cv2 module) the function is not needed, since cv2 can process Numpy arrays (and this is the only supported array type).
In the docs of OpenCV 3.1.0 the method fromarray does not exist anymore.

Categories