Python - Writing your own function with opencv giving an error - python

import numpy as np
import cv2
def resize(image, percentage):
img = image
fy=percentage
fx=percentage
img2 = cv2.resize(img, (0,0), fx, fy)
return cv2.img2
img = cv2.imread('test.png')
img2 = resize(img, 0.45)
cv2.imshow('image',img2)
cv2.waitKey(0)
cv2.destroyAllWindows()
Traceback (most recent call last):
File "C:\Users\Jay\Desktop\Portable Python\opencvprogram_ver1.py", line 14, in <module>
img2 = resize(img, 0.45)
File "C:\Users\Jay\Desktop\Portable Python\opencvprogram_ver1.py", line 10, in resize
img2 = cv2.resize(img, (0,0), fx, fy)
error: C:\builds\master_PackSlaveAddon-win32-vc12-static\opencv\modules\imgproc\src\imgwarp.cpp:3209: error: (-215) dsize.area() > 0 || (inv_scale_x > 0 && inv_scale_y > 0) in function cv::resize
Dear Python Council members,
I've been learning Python and OpenCV and I ran into a problem here.
I'm trying to see if it's possible to include an OpenCV function in my own function, but it seems like I'm doing this wrong. The traceback says something something about dsize.area in cv::resize, but this error message means very little too me because I do not know how this works in the smaller picture.
Can someone guide me in the right direction so the program works as I'd expect?
Thank you very much.

What you have looks almost right. Just change the last two lines of the function to:
img2 = cv2.resize(img, (0,0), fx=fx, fy=fy) # enter fx and fy as keyword arguments
return img2 # cv2.img2 was just a typo
Since fx and fy are not the 3rd and 4th arguments of the function, you have to specify them as keyword arguments.

Related

RGB to Grayscale (Average Method) Python

I'm supposed to write a method that converts an RGB image to Grayscale by using the "average method" where I take the average of the 3 colors (not the weighted method or luminosity method). I then must display the original RGB image and grayscale image next to each other (concatenated). The language I'm writing in is Python. This is what my code looks like currently.
import numpy as np
import cv2
def getRed(redVal):
return '#%02x%02x%02x' % (redVal, 0, 0)
def getGreen(greenVal):
return '#%02x%02x%02x' % (0, greenVal, 0)
def getBlue(blueVal):
return '#%02x%02x%02x' % (0, 0, blueVal)
# Grayscale = (R + G + B / 3)
# For each pixel,
# 1- Get pixels red, green, and blue
# 2- Calculate the average value
# 3- Set each of red, green, and blue values to average value
def average_method(img):
for p in img:
red = p.getRed()
green = p.getGreen()
blue = p.getBlue()
average = (red + green + blue) / 3
p.setRed(average)
p.setGreen(average)
p.setBlue(average)
def main():
img1 = cv2.imread('html/images/sun.jpeg')
img1 = cv2.resize(img1, (0, 0), None, .50, .50)
img2 = average_method(img1)
img2 = np.stack(3 * [img2], axis=2)
numpy_concat = np.concatenate((img1, img2), 1)
cv2.imshow('Numpy Concat', numpy_concat)
cv2.waitKey(0)
cv2.destroyAllWindows
if __name__ =="__main__":
main()
The portion that is commented within the average_method function is the steps that I must follow.
When I try to run the code, I get
File "test.py", line 38, in <module>
main()
File "test.py", line 30, in main
img2 = average_method(img1)
File "test.py", line 15, in average_method
red = p.getRed()
AttributeError: 'numpy.ndarray' object has no attribute 'getRed'
I thought that defining the functions for getRed, getGreen, and getBlue up above would mean they'd become recognizable in my average_method function (I got those functions from online so I hope they're right). I'm also not sure what it has to do with numpy.ndarray. If anyone could help me fill in this average_method function with code that follows the commented steps correctly, I would really appreciate it.
EDIT:::
New code looks like this:
import cv2
import numpy as np
def average_method(img):
for p in img:
gray = sum(p)/3
for i in range(3):
p[i] = gray
def main():
img1 = cv2.imread('html/images/sun.jpeg')
img1 = cv2.resize(img1, (0, 0), None, .50, .50)
img2 = average_method(img1)
img2 = np.stack(3 * [img2], axis=2)
numpy_concat = np.concatenate((img1, img2), 1)
cv2.imshow('Numpy Concat', numpy_concat)
cv2.waitKey(0)
cv2.destroyAllWindows
if __name__ =="__main__":
main()
I now get the error
File "test.py", line 50, in <module>
main()
File "test.py", line 43, in main
img2 = np.stack(3 * [img2], axis=2)
File "<__array_function__ internals>", line 5, in stack
File "C:\Users\myname\AppData\Local\Programs\Python\Python38-32\lib\site-packages\numpy\core\shape_base.py", line 430, in stack
axis = normalize_axis_index(axis, result_ndim)
numpy.AxisError: axis 2 is out of bounds for array of dimension 1
I have that line "img2 = np.stack(3 * [img2], axis=2)" since I was previously told on Stack Overflow I need it due to my img2 now being a greyscale (single-channel) image, when img1 is still color (three-channel). This line apparently fixes that. But now it seems like there is something wrong with that?
In Java, the for loop you highlighted is called an "enhanced for loop". Python doesn't have these because Python for loops pog (in terms of concision).
The Python equivalent of the line in question would be:
for p in img:
No need to state object class or anything like that.
EDIT: After OP changed question
The problem now is that you're not calling the functions correctly. p is an array containing the RGB values for that pixel. To call the function as you defined above do:
for p in img:
red = getRed(p[0])
green = getGreen(p[1])
blue = getBlue(p[2])
average = (red + green + blue) / 3
p[0] = average
p[1] = average
p[2] = average
Remember when you moved the code to Python, you seem to no longer be working in Object Oriented Programming! Pixels don't come with methods that you can call like that anymore.
However, as pointed out by Guimoute in the comments, the code can be much simpler if you get rid of the get[Color] functions and do the following:
for p in img:
gray = sum(p)/3
for i in range(3):
p[i] = gray

Python: OpenCV: How to get an undistorted image without the cropping?

This is similar to nkint's question from September 11, 2013. Link is here:
how to get all undistorted image with opencv
I'm a new user, so I didn't have enough reputation/clout to comment on the OP.
I have tried to emulate the code andrewmkeller posted, using Python instead of C++, with some minor changes based on Josh Bosch's response. The result is the following:
#!/usr/bin/env python
import cv2
import numpy as np
def loadUndistortedImage(fileName):
# load image
image = cv2.imread(fileName)
#print(image)
# set distortion coeff and intrinsic camera matrix (focal length, centerpoint offset, x-y skew)
cameraMatrix = np.array([[894.96803896,0,470.38713516],[0,901.32629374,922.41232898], [0,0,1]])
distCoeffs = np.array([[-0.340671222,0.110426603,-.000867987573,0.000189669273,-0.0160049526]])
# setup enlargement and offset for new image
y_shift = 60 #experiment with
x_shift = 70 #experiment with
imageShape = image.shape #image.size
print(imageShape)
imageSize = (int(imageShape[0])+2*y_shift, int(imageShape[1])+2*x_shift, 3)
print(imageSize)
# create a new camera matrix with the principal point offest according to the offset above
newCameraMatrix, validPixROI = cv2.getOptimalNewCameraMatrix(cameraMatrix, distCoeffs, imageSize,
1)
#newCameraMatrix = cv2.getDefaultNewCameraMatrix(cameraMatrix, imageSize, True) # imageSize, True
# create undistortion maps
R = np.array([[1,0,0],[0,1,0],[0,0,1]])
map1, map2 = cv2.initUndistortRectifyMap(cameraMatrix, distCoeffs, R, newCameraMatrix, imageSize,
cv2.CV_16SC2)
# remap
outputImage = cv2.remap(image, map1, map2, INTER_LINEAR)
#save output image as file with "FIX" appened to name - only works with .jpg files at the moment
index = filename.find('.jpg')
fixed_filename = filename[:index] +'_undistorted'+fileName[index:]
cv2.imwrite(fixed_filename, outputImage)
cv2.imshow('fix_img',outputImage)
cv2.waitKey(0)
return
#Undistort the images, then save the restored images
loadUndistortedImage('./calib/WIN_20200626_11_29_16_Pro.jpg')
This seemed good to me, but then problems came up when trying to use cv2.getOptimalNewCameraMatrix or cv2.getDefaultNewCameraMatrix and cv2.initUndistortRectifyMap. I kept getting told that 'the argument takes exactly 2 arguments (3 given)' even though I am putting the parameters as specified in their documentation here:
https://docs.opencv.org/2.4/modules/calib3d/doc/camera_calibration_and_3d_reconstruction.html
https://docs.opencv.org/2.4/modules/imgproc/doc/geometric_transformations.html
I can remove the error from "...getDefault..." if I remove the optional params, but I'd rather not do that.
Stacktrace:
Traceback (most recent call last):
File ".\main.py", line 46, in <module>
loadUndistortedImage('./<image file name>.jpg')
File ".\main.py", line 27, in loadUndistortedImage
newCameraMatrix, validPixROI = cv2.getOptimalNewCameraMatrix(cameraMatrix, distCoeffs, imageSize, 1)
TypeError: function takes exactly 2 arguments (3 given)
I don't have enough reputation to comment, but you could try:
newcameramatrix, _ = cv2.getOptimalCameraMatrix(
camera_matrix, dist_coeffs, (width, height), 1, (width, height)
)
According to this, that's how the function should be called.
Now, instead of getting the undistorted image with cv2.initUndistortRectifyMap, you could just do:
undistorted_image = cv2.undistort(
image, camera_matrix, dist_coeffs, None, newcameramatrix
)
cv2.imshow("undistorted", undistorted_image)
Following up to my comment on Sebastian Liendo's answer, and also thanks to a Finnish responder on Github (whose Issues are not for these sort of general questions, I learned), here is 1) the updated documentation for the python functions, and 2) the heart of my revised code which does a decent job of getting around the cropping. (Don't do what I did in the question and post the ENTIRE code, just the part essential to your question.)
https://docs.opencv.org/4.3.0/d9/d0c/group_calib3d.html#ga7a6c4e032c97f03ba747966e6ad862b1
#load image
image = cv2.imread(fileName)
#images = glob.glob(pathName + '*.jpg') #loop within a specified directory
#for fileName in images:
#image = cv2.imread(fileName)
#set camera parameters
height, width = image.shape[:2]
cameraMatrix = np.array([[894.96803896,0,470.38713516],[0,901.32629374,922.41232898], [0,0,1]])
distCoeffs = np.array([[-0.340671222,0.110426603,-.000867987573,0.000189669273,-0.0160049526]])
#create new camera matrix
newCameraMatrix, validPixROI = cv2.getOptimalNewCameraMatrix(cameraMatrix, distCoeffs,(width, height), 1, (width, height))
#undistort
outputImage = cv2.undistort(image, cameraMatrix, distCoeffs, None, newCameraMatrix)
#crop, modified
x, y, w, h = validPixROI #(211, 991, 547, 755)
outputImage = outputImage[y-200:y+h+200, x-40:x+w+80] #fudge factor to minimize cropping
THE ONE CAVEAT: this code still crops a bit of the outer-trim of the original capture, but not by much. Minimizing that cropping is the reason for the fudge factor I put in the ouputImage = outputImage[...] line.

Getting Error: (-215:Assertion failed) When Using seamlessClone

For clarity, I am a beginner in Python. I'm creating a script that replaces the eyes with a robotic one from a series of images in a folder. I'm stuck on the seamlessClone function that keeps throwing this error.
The code is incomplete as far as writing out the entire script (it only clones one eye so far), but everything should be working. I've been stuck on this one for 6 hours and thought I would ask on here.
I've tried checking my filenames, paths, seeing if the image file was corrupt by using print, changing the image files with different dimensions, filetypes (png, jpg) and so on.
I've also tried converting every numpy array(cv2_image, Eye) into a 32bit array to see if that was the issue, but nothing prevailed.
# Import
from PIL import Image, ImageDraw, ImageFilter
from statistics import mean
import face_recognition
import cv2
import glob
import numpy as np
# Open Eye Images
Eye = cv2.imread('eye.jpg')
# Loop Through Images
for filename in glob.glob('images/*.jpg'):
cv2_image = cv2.imread(filename)
image = face_recognition.load_image_file(filename)
face_landmarks_list = face_recognition.face_landmarks(image)
for facemarks in face_landmarks_list:
# Get Eye Data
eyeLPoints = facemarks['left_eye']
eyeRPoints = facemarks['right_eye']
npEyeL = np.array(eyeLPoints)
npEyeR = np.array(eyeRPoints)
# Create Mask
mask = np.zeros(cv2_image.shape, cv2_image.dtype)
mask.fill(0)
poly = np.array([eyeLPoints])
cv2.fillPoly(mask, [poly], (255,255, 255))
# Get Eye Image Centers
npEyeL = np.array(eyeLPoints)
eyeLCenter = npEyeL.mean(axis=0).astype("int")
x1 = (eyeLCenter[0])
x2 = (eyeLCenter[1])
print(x1, x2)
# Get Head Rotation (No code yet)
# Apply Seamless Clone To Main Image
saveImage = cv2.seamlessClone(Eye, cv2_image, mask ,(x1, x2) , cv2.NORMAL_CLONE)
# Output and Save
cv2.imwrite('output/output.png', saveImage)
Here is the full error:
Traceback (most recent call last):
File "stack.py", line 45, in <module>
saveImage = cv2.seamlessClone(Eye, cv2_image, mask ,(x1, x2) , cv2.NORMAL_CLONE)
cv2.error: OpenCV(4.1.1) /io/opencv/modules/core/src/matrix.cpp:466: error: (-215:Assertion failed) 0 <= roi.x && 0 <= roi.width && roi.x + roi.width <= m.cols && 0 <= roi.y && 0 <= roi.height && roi.y + roi.height <= m.rows in function 'Mat'
The result I'm expecting is for the eye image to be cloned onto the original image, but this error keeps being thrown, preventing me from completing the script. If there were any hint as to what's going on, I feel that the culprit is the "Eye" file, but I could be wrong. Any help would be appreciated.
There are two sets of keypoints:
There is a set of keypoints for the eye in the destination image:
There is a set of keypoints for the eye in the source image:
You are using the wrong set of keypoints to make the mask for the cv2.seamlessClone() function. You should be using the keypoints from the source image. The mask needs to be a TWO channel image, in your code (among the other problems) you are using a THREE channel image.
This is the result. You can see there should also be a resize function to match the sizes of the eyes:
This is the code that I used:
import face_recognition
import cv2
import numpy as np
# Open Eye Images
eye = cv2.imread('eye.jpg')
# Open Face image
face = cv2.imread('face.jpeg')
# Get Keypoints
image = face_recognition.load_image_file('face.jpeg')
face_landmarks_list = face_recognition.face_landmarks(image)
for facemarks in face_landmarks_list:
# Get Eye Data
eyeLPoints = facemarks['left_eye']
eyeRPoints = facemarks['right_eye']
npEyeL = np.array(eyeLPoints)
# These points define the contour of the eye in the EYE image
poly_left = np.array([(51, 228), (100, 151), (233, 102), (338, 110), (426, 160), (373, 252), (246, 284), (134, 268)], np.int32)
# Create a mask for the eye
src_mask = np.zeros(face.shape, face.dtype)
cv2.fillPoly(src_mask, [poly_left], (255, 255, 255))
cv2.imwrite('src_mask.png', src_mask)
# Find where the eye should go
center, r = cv2.minEnclosingCircle(npEyeL)
center = tuple(np.array(center, int))
# Clone seamlessly.
output = cv2.seamlessClone(eye, face, src_mask, center, cv2.NORMAL_CLONE)

OpenCV/Python: Error in cv2.add() to add a number to image

I'm using OpenCV/Python and I'm trying to add a number to image.
My code is:
import cv2
import numpy as np
import math
from matplotlib import pyplot as plt
img = cv2.imread('messi.jpg',0)
img2 = img
img2 = cv2.add(img2, np.uint8([50]))
I got the next error:
OpenCV Error: Assertion failed (type2 == CV_64F && (sz2.height == 1 || sz2.heigh
t == 4)) in cv::arithm_op, file C:\builds\master_PackSlaveAddon-win64-vc12-stati
c\opencv\modules\core\src\arithm.cpp, line 1989
Traceback (most recent call last):
File "lab3_examples.py", line 27, in <module>
img2 = cv2.add(img, np.uint8([50]))
cv2.error: C:\builds\master_PackSlaveAddon-win64-vc12-static\opencv\modules\core
\src\arithm.cpp:1989: error: (-215) type2 == CV_64F && (sz2.height == 1 || sz2.h
eight == 4) in function cv::arithm_op
The image I'm using is messi.jpg
Instead, if I use img2 = np.add(img2, np.uint8([50])) intensities that pass the value 255 the value % 255 result, e.g. 260%255=4 the pixel's value is set to 4 instead of 255. As a result, white pixels are turned to black!
Here is the faulty resulted image.
Any ideas please?
In C++ for this purpose saturate_cast(...) is used.
In Python simply
img2 = cv2.add(img2, 50)
will do, if you want to increase brightness for gray-scale image. If implied to colored, color balance will be shifted. For colored image, to save the balance, good answer is by Alex, Bill Grates:
How to fast change image brightness with python + OpenCV?
The only remark - next part of code are not nessessary:
v[v > 255] = 255
v[v < 0] = 0
in my case (Python3,Opencv4).
I would suggest convert the BGR image to HSV image:
hsv= cv2.cvtColor(image, cv2.COLOR_BGR2HSV)
Then split the channels using:
h_channel, s_channel, v_channel = cv2.split(hsv)
Now play with the h_channel:
h_channel + = 20 #---You can try any other value as well---
Now merge the channels back together again:
merged = cv2.merge((h_channel , s_channel , v_channel ))
Finally convert the image back to BGR and display it:
Final_image = cv2.cvtColor(merged, cv2.COLOR_HSV2BGR)
cv2.imshow('Final output', Final_image)
You will see an enhanced or a dimmed image depending on the value you add.
Hope it helps.... :D

OpenCV Python HoughCircles error

I'm working on a program that detects circular shapes in images. I decided a Hough Transform would be the best, and I found one in the OpenCV library. The problem is that when I try to use it I get an error that I have no idea how to fix. Is OpenCV for Python not fully implemented? Is there a fix to the library I need for the program to work?
Here's the code:
import cv
#cv.NamedWindow("camera", 1)
capture = cv.CaptureFromCAM(0)
while True:
img = cv.QueryFrame(capture)
gray = cv.CreateImage(cv.GetSize(img), 8, 1)
edges = cv.CreateImage(cv.GetSize(img), 8, 1)
cv.CvtColor(img, gray, cv.CV_BGR2GRAY)
cv.Canny(gray, edges, 50, 200, 3)
cv.Smooth(gray, gray, cv.CV_GAUSSIAN, 9, 9)
storage = cv.CreateMat(1, 2, cv.CV_32FC3)
#This is the line that throws the error
cv.HoughCircles(edges, storage, cv.CV_HOUGH_GRADIENT, 2, gray.height/4, 200, 100)
#cv.ShowImage("camera", img)
if cv.WaitKey(10) == 27:
break
And here is the error I'm getting:
OpenCV Error: Null pinter () in unknown function,
file ..\..\..\..\ocv\openc\src\cxcore\cxdatastructs.cpp, line 408
Traceback (most recent call last):
File "ellipse-detect-webcam.py", line 20, in
cv.HoughCircles(edges, storage, cv.CV_HOUGH_GRADIENT, 2, gray.height/4, 200, 100)
cv.error
Thanks in advance for the help.
For what it's worth, I've found that cv.HoughCircles aborts if it can't detect a circular shape in the image, instead of gracefully returning an empty list.
Are the images valid?
Can you display them (the original and the grayscaled)
Otherwise are you sure the args to the function are correct? Are you passing pointers or references correctly
The storage must to be bigger, I thought that cvMat isn't dinamically allocated so you have to for example change the line:
storage = cv.CreateMat(1, 2, cv.CV_32FC3)
to:
storage = cv.CreateMat(1, img.rows * img.cols, cv.CV_32FC3)

Categories