This is the modified code from what I found here.
import numpy as np
import cv2
from matplotlib import pyplot as plt
img = cv2.imread('digits.png')
gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
# Now we split the image to 5000 cells, each 20x20 size
cells = [np.hsplit(row,100) for row in np.vsplit(gray,50)]
# Make it into a Numpy array. It size will be (50,100,20,20)
x = np.array(cells)
# Now we prepare train_data.
train = x[:,:50].reshape(-1,400).astype(np.float32) # Size = (2500,400)
img = cv2.imread('1.png')
img1 = cv2.imread('2.png')
img = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
img1 = cv2.cvtColor(img1,cv2.COLOR_BGR2GRAY)
img = cv2.resize(img, (20,20)).astype(np.float32)
img1 = cv2.resize(img1, (20,20)).astype(np.float32)
img = img.flatten()
img1 = img1.flatten()
arr = [img,img1]
arr = np.asarray(arr)
# Create labels for train and test data
k = np.arange(10)
train_labels = np.repeat(k,250)[:,np.newaxis]
# Initiate kNN, train the data, then test it with test data for k=1
knn = cv2.ml.KNearest_create()
knn.train(train, 0,train_labels)
ret, result, neighbours, dist = knn.findNearest(arr, k=5)
for i in result:
print i
# save the data
np.savez('knn_data.npz',train=train, train_labels=train_labels)
# Now load the data
with np.load('knn_data.npz') as data:
print data.files
train = data['train']
train_labels = data['train_labels']
which works perfectly. But I can't figure out, how to use this knn_data.npz file.
This was my attempt:
import numpy as np
import cv2
from matplotlib import pyplot as plt
with np.load('knn_data.npz') as data:
print data.files
train = data['train']
train_labels = data['train_labels']
img = cv2.imread('1.png')
img1 = cv2.imread('2.png')
img = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
img1 = cv2.cvtColor(img1,cv2.COLOR_BGR2GRAY)
img = cv2.resize(img, (20,20)).astype(np.float32)
img1 = cv2.resize(img1, (20,20)).astype(np.float32)
img = img.flatten()
img1 = img1.flatten()
arr = [img,img1]
arr = np.asarray(arr)
knn = cv2.ml.KNearest_create()
ret, result, neighbours, dist = knn.findNearest(arr, k=5)
for i in result:
print i
The error message I got, which I could not fix was:
OpenCV Error: Assertion failed (test_samples.type() == 5 && test_samples.cols == samples.cols) in findNearest, file /io/opencv/modules/ml/src/knearest.cpp, line 325
Traceback (most recent call last):
File "knn1.py", line 20, in
ret, result, neighbours, dist = knn.findNearest(img, k=5)
cv2.error: /io/opencv/modules/ml/src/knearest.cpp:325: error: (-215) test_samples.type() == 5 && test_samples.cols == samples.cols in function findNearest
I am using opencv 3.2.0 on python 2.7.15 in ubuntu 18.04. The files 1.png and 2.png are RGB-image files.
In your example, you create the variables train and train_labels but never use them.
Add the following anywhere before you call knn.findNearest(arr, k=5):
train = data['train']
train_labels = data['train_labels']
knn = cv2.ml.KNearest_create()
knn.train(train, 0,train_labels)
Related
Apologies in advance as i am newbie to OpenCV-Python. I set myself a task to create a Passport type image from the video capture.
Using a head and shoulders Haar Cascade i was able to create a portrait photo but i now want to turn the background to a white background (leaving the head and shoulders portrait in the foreground).
Just not sure how/ best way to do this. Any help would be welcome.
Many thanks in advance.
Here is the code:
import numpy as np
import cv2
# face file
face_cascade = cv2.CascadeClassifier('haarcascade_frontalface_default.xml')
# eye file
eye_cascade = cv2.CascadeClassifier('haarcascade_eye.xml')
# head shoulders file
hs_cascade = cv2.CascadeClassifier('HS.xml')
cap = cv2.VideoCapture(1)
while 1:
ret, img = cap.read()
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
headshoulders = hs_cascade.detectMultiScale(gray, 1.3, 3)
# find the head and shoulders
for (x,y,w,h) in headshoulders:
# variable change to make portrait orientation
x = int(x*1.5)
w = int(w/1.5)
cv2.rectangle(img,(x,y),(x+w,y+h),(255,0,0),2)
# crop the image
crop_img = img[y: y + h, x: x + w]
# show original and crop
cv2.imshow('crop', crop_img)
cv2.imshow('img', img)
k = cv2.waitKey(30) & 0xff
if k == 27:
break
elif k == ord('s'):
# save out the portrait image
cv2.imwrite('cropimage.png',crop_img)
# release the camera
cap.release()
cv2.destroyAllWindows()
I got it to work. Here is my solution.
PLEASE NOTE: This worked for HI-RES images (Nikon D7100 - JPEG). LOW-RES did NOT work when i tried a Webcam (Logitech C615).
I used some of the code from a link that was suggested.
# import numpy
import numpy as np
# import cv2
import cv2
# import Matplitlib
from matplotlib import pyplot as plt
# Fill any holes function
def get_holes(image, thresh):
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
im_bw = cv2.threshold(gray, thresh, 255, cv2.THRESH_BINARY)[1]
im_bw_inv = cv2.bitwise_not(im_bw)
im_bw_inv, contour, _ = cv2.findContours(im_bw_inv, cv2.RETR_CCOMP, cv2.CHAIN_APPROX_SIMPLE)
for cnt in contour:
cv2.drawContours(im_bw_inv, [cnt], 0, 255, -1)
nt = cv2.bitwise_not(im_bw)
im_bw_inv = cv2.bitwise_or(im_bw_inv, nt)
return im_bw_inv
# Remove background Function
def remove_background(image, thresh, scale_factor=.25, kernel_range=range(1, 15), border=None):
border = border or kernel_range[-1]
holes = get_holes(image, thresh)
small = cv2.resize(holes, None, fx=scale_factor, fy=scale_factor)
bordered = cv2.copyMakeBorder(small, border, border, border, border, cv2.BORDER_CONSTANT)
for i in kernel_range:
#kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (2*i+1, 2*i+1))
kernel = cv2.getStructuringElement(cv2.MORPH_CROSS, (2*i+1, 2*i+1))
bordered = cv2.morphologyEx(bordered, cv2.MORPH_CLOSE, kernel)
unbordered = bordered[border: -border, border: -border]
mask = cv2.resize(unbordered, (image.shape[1], image.shape[0]))
fg = cv2.bitwise_and(image, image, mask=mask)
return fg
# Load a color image in grayscale
img = cv2.imread('original/11.png')
# Start background removal -- Parameters are <image> and <threshold level>
nb_img = remove_background(img, 180)
# Change Black Pixels to WHITE
nb_img[np.where((nb_img==[0,0,0]).all(axis=2))] = [255,255,255]
# resize the viewing size (as the images are too big for the screen
small = cv2.resize(nb_img, (300, 400))
# Show the finished image
cv2.imshow('image',small)
k = cv2.waitKey(0) & 0xFF
if k == 27: #wait for ESC key to exit
# if ESC pressed close the camera windows
cv2.destroyAllWindows()
elif k == ord('s'): #wait for 's' key to save and exit
# Save the img(greyscale version)
cv2.imwrite('bg_removal/11.png',small)
cv2.destroyAllWindows()
I am trying to detect well-defined blobs in some images, I can easily threshold the image to have just the white spots I want to detect but the blob detector seems to group some of them together or miss others. Is there a better way to do this? Is there some way to find every island of connected white pixels that is not super slow?
Thresholded image:
Detected Blobs:
The code used to process the Threshold into blobs:
import numpy as np
import cv2
params = cv2.SimpleBlobDetector_Params()
# we are looking for white blobs in a mask
params.blobColor = 255
params.filterByColor = True
params.filterByArea = True
params.minArea = 0
# Blobs larger than 50 pixels are noise
params.maxArea = 50
# enabling these can cause us to miss points
params.filterByCircularity = False
params.filterByConvexity = False
params.filterByInertia = False
detector = cv2.SimpleBlobDetector_create(params)
img = cv2.imread('Threshold Out.png', flags=cv2.IMREAD_GRAYSCALE)
keypoints = detector.detect(img)
img = cv2.cvtColor(img, cv2.COLOR_GRAY2RGB)
img = cv2.drawKeypoints(img, keypoints, np.array([]), (0, 0, 255),
cv2.DRAW_MATCHES_FLAGS_DRAW_RICH_KEYPOINTS)
while True:
cv2.imshow('out', img)
key = cv2.waitKey(0)
if key == 27:
break
After reading through the C docs for the blob detector params there is a parameter called minDistBetweenBlobs and setting this to 1 solved my issue.
Detected Blobs:
Updated code:
import numpy as np
import cv2
params = cv2.SimpleBlobDetector_Params()
# we are looking for white blobs in a mask
params.blobColor = 255
params.filterByColor = True
params.filterByArea = True
params.minDistBetweenBlobs = 1
params.minArea = 0
# Blobs larger than 50 pixels are noise
params.maxArea = 50
# enabling these can cause us to miss points
params.filterByCircularity = False
params.filterByConvexity = False
params.filterByInertia = False
detector = cv2.SimpleBlobDetector_create(params)
img = cv2.imread('Threshold Out.png', flags=cv2.IMREAD_GRAYSCALE)
keypoints = detector.detect(img)
img = cv2.cvtColor(img, cv2.COLOR_GRAY2RGB)
img = cv2.drawKeypoints(img, keypoints, np.array([]), (0, 0, 255),
cv2.DRAW_MATCHES_FLAGS_DRAW_RICH_KEYPOINTS)
while True:
cv2.imshow('out', img)
key = cv2.waitKey(0)
if key == 27:
break
I would like to get images from server side and display them on client side by pygame and not save each frame on disk. images are transferred using base64 encode and decode. when data is received from the other side it is decoded to PIL image. Then i can successfully save it to a temporary file ,open it with pygame and display it. however I would like to do it directly using image.tostring() but noting is displayed I am also noticed that when i save to temporary file pictures attributes are:
Surface(32x32x32 SW)
and when I do it directly:
Surface(32x32x8 SW)
thanks:
import base64
from io import BytesIO
import pygame
from PIL import Image
def gif__to_string(filePath):
gif_file = filePath
content = base64.encodestring(open(gif_file, 'rb').read())
return content
def string_to_gif(imageStr):
gif_image = Image.open(BytesIO(base64.b64decode(imageStr)))
return gif_image
def show_gif_working(im):
black = (0, 0, 0)
white = (255, 255, 255)
pygame.init()
width = 350;
height = 400
imageX = 200; # x coordnate of image
imageY = 30; #
screen = pygame.display.set_mode((width, height))
screen.fill(black)
im.save('temp.gif')
surface = pygame.image.load("temp.gif").convert()
screen.blit(surface, (imageY, imageY))
pygame.display.flip()
def show_gif_not_working(im):
black = (0, 0, 0)
white = (255, 255, 255)
pygame.init()
width = 350;
height = 400
imageX = 200; # x coordnate of image
imageY = 30; #
screen = pygame.display.set_mode((width, height))
screen.fill(black)
mode = im.mode
size = im.size
data = im.tostring()
surface1 = pygame.image.fromstring(data, size, mode)
screen.blit(surface1, (imageX, imageY))
pygame.display.flip()
def main():
content = gif__to_string('face5.gif')
print content
myImage = string_to_gif(content)
# show_gif_working(myImage)
show_gif_not_working(myImage)
main()
Have you tried using pygame.image.load[1] with a file-like object instead of a string?
You could pass a StringIO[2] object instead of a file.
I have the same problem!
The code from the top of this thread works with jpg-files, but now with gif's.
The simple idea with:
myimage = Image.open("test.gif")
pyimage = pygame.image.load(myimage)
puts out an error:
Traceback (most recent call last):
File "example.py", line 12, in <module>
pyimage = pygame.image.load(myimage)
TypeError: not a file object
I use Python 3.7 with the function:
pg.image.frombuffer(), or pg.image.fromstring()
The details:
import PIL.Image as Image
import pygame as pg
gif = Image.open('file.gif')
for i in range(gif.n_frames):
gif.seek(i)
surf = pg.image.frombuffer(gif.tobytes(), gif.size, gif.mode)
gif.seek(i) is to locate the gif to a unique position,
and the surf the Surface object that you want.
I am trying to create a program that will show me different types of gradients of a video I am capturing. This is my code:
import cv2
import numpy as np
from matplotlib import pyplot as plt
cap = cv2.VideoCapture()
while(1):
bleh, img = cap.read()
laplacian = cv2.Laplacian(img,cv2.CV_64F)
sobelx = cv2.Sobel(img,cv2.CV_64F,1,0,ksize=5)
sobely = cv2.Sobel(img,cv2.CV_64F,0,1,ksize=5)
plt.subplot(2,2,1),plt.imshow(img,cmap = 'gray')
plt.title('Original'), plt.xticks([]), plt.yticks([])
plt.subplot(2,2,2),plt.imshow(laplacian,cmap = 'gray')
plt.title('Laplacian'), plt.xticks([]), plt.yticks([])
plt.subplot(2,2,3),plt.imshow(sobelx,cmap = 'gray')
plt.title('Sobel X'), plt.xticks([]), plt.yticks([])
plt.subplot(2,2,4),plt.imshow(sobely,cmap = 'gray')
plt.title('Sobel Y'), plt.xticks([]), plt.yticks([])
plt.show()
However, I am getting an error stating that Image data can not be converted to float.
This program works when I replace the video capturing with just an image and feed that directly into the laplacian, sobelx, and sobely transformations.
Can I not sure matplot for video?
I had the same problem with your code then I changed :
cap = cv2.VideoCapture()
to :
cap = cv2.VideoCapture(0)
and it worked
This is because VideoCapture needs to know what video device to use on your computer, if you are using your webcam then you have to pass 0 as argument to the function
I am attempting to create a main function that will use the program below with a webcam to display what cards are being detected on the screen currently. what would be the best way to do this? any help is appreciated.
"""
Usage:
./card_img.py filename, num_cards, training_image_filename, training_labels_filename, num_training_cards
Example:
./card_img.py test.JPG 4 train.png train.tsv 56
"""
import sys
import numpy as np
sys.path.insert(0, "/usr/local/lib/python2.7/site-packages/")
import cv2
###############################################################################
# Utility code
###############################################################################
def rectify(h):
#//changes the array of the picture\\
h = h.reshape((4,2))
hnew = np.zeros((4,2),dtype = np.float32)
add = h.sum(1)
hnew[0] = h[np.argmin(add)]
hnew[2] = h[np.argmax(add)]
diff = np.diff(h,axis = 1)
hnew[1] = h[np.argmin(diff)]
hnew[3] = h[np.argmax(diff)]
return hnew
###############################################################################
# Image Matching
###############################################################################
def preprocess(img):
#Example: test_img = cv2.imread("test.JPG")
# preprocess(test_img)
gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
blur = cv2.GaussianBlur(gray,(5,5),2 )
thresh = cv2.adaptiveThreshold(blur,255,1,1,11,1)
return thresh
def imgdiff(img1,img2):
img1 = cv2.GaussianBlur(img1,(5,5),5)
img2 = cv2.GaussianBlur(img2,(5,5),5)
diff = cv2.absdiff(img1,img2)
diff = cv2.GaussianBlur(diff,(5,5),5)
flag, diff = cv2.threshold(diff, 200, 255, cv2.THRESH_BINARY)
return np.sum(diff)
def find_closest_card(training,img):
features = preprocess(img)
return sorted(training.values(), key=lambda x:imgdiff(x[1],features))[0][0]
###############################################################################
# Card Extraction
###############################################################################
def getCards(im, numcards=4):
#Example: test = cv2.imread("test.JPG") //also works with 1 arg(file)\\
# getCards(test,2)
#or: getCards("test.jpg",2)
gray = cv2.cvtColor(im,cv2.COLOR_BGR2GRAY)
blur = cv2.GaussianBlur(gray,(1,1),1000)
flag, thresh = cv2.threshold(blur, 120, 255, cv2.THRESH_BINARY)
contours, hierarchy = cv2.findContours(thresh,cv2.RETR_TREE,cv2.CHAIN_APPROX_SIMPLE)
contours = sorted(contours, key=cv2.contourArea,reverse=True)[:numcards]
for card in contours:
peri = cv2.arcLength(card,True)
approx = rectify(cv2.approxPolyDP(card,0.02*peri,True))
# box = np.int0(approx)
# cv2.drawContours(im,[box],0,(255,255,0),6)
# imx = cv2.resize(im,(1000,600))
# cv2.imshow('a',imx)
h = np.array([ [0,0],[449,0],[449,449],[0,449] ],np.float32)
transform = cv2.getPerspectiveTransform(approx,h)
warp = cv2.warpPerspective(im,transform,(450,450))
yield warp
def get_training(training_labels_filename,training_image_filename,num_training_cards,avoid_cards=None):
#Example: get_training("train.tsv","train.png",4,None)
training = {}
labels = {}
for line in file(training_labels_filename):
key, num, suit = line.strip().split()
labels[int(key)] = (num,suit)
print "Training"
im = cv2.imread(training_image_filename)
for i,c in enumerate(getCards(im,num_training_cards)):
if avoid_cards is None or (labels[i][0] not in avoid_cards[0] and labels[i][1] not in avoid_cards[1]):
training[i] = (labels[i], preprocess(c))
print "Done training"
return training
if __name__ == '__main__':
if len(sys.argv) == 6:
filename = sys.argv[1]
num_cards = int(sys.argv[2])
training_image_filename = sys.argv[3]
training_labels_filename = sys.argv[4]
num_training_cards = int(sys.argv[5])
training = get_training(training_labels_filename,training_image_filename,num_training_cards)
im = cv2.imread("test.")
width = im.shape[0]
height = im.shape[1]
if width < height:
im = cv2.transpose(im)
im = cv2.flip(im,1)
# Debug: uncomment to see registered images
#for i,c in enumerate(getCards(im,num_cards)):
# card = find_closest_card(training,c,)
# cv2.imshow(str(card),c)
# cv2.waitKey(0)
cards = [find_closest_card(training,c) for c in getCards(im,num_cards)]
print cards
else:
print __doc__
Build open cv with nonfree modules and use SURF Features. They are awesome and can detect and seperate almost everything:
http://docs.opencv.org/master/doc/py_tutorials/py_feature2d/py_surf_intro/py_surf_intro.html
Here are some Code examples (sorry just C++ not python): http://docs.opencv.org/doc/user_guide/ug_features2d.html
This is the important code:
// detecting keypoints
SurfFeatureDetector detector(400);
vector<KeyPoint> keypoints1, keypoints2;
detector.detect(img1, keypoints1);
detector.detect(img2, keypoints2);
// computing descriptors
SurfDescriptorExtractor extractor;
Mat descriptors1, descriptors2;
extractor.compute(img1, keypoints1, descriptors1);
extractor.compute(img2, keypoints2, descriptors2);
// matching descriptors
BruteForceMatcher<L2<float> > matcher;
vector<DMatch> matches;
matcher.match(descriptors1, descriptors2, matches);
If speed matter you can use
cv::FlannBasedMatcher matcher;
std::vector< cv::DMatch > matches;
matcher.match( descriptors_this, descriptors_givenImage, matches );
Where FLANN is just a very cool, very fast framework which uses a lot of methods like tree, bvhs and other stuff to speed things up a lot.
Here are some answers if you need help with installing surf: OpenCV - undefined reference: SurfFeatureDetector and BruteForceMatcher