Converting OpenCV code snippet from C++ to Python - python

I'm trying to convert this code to python.
can anyone help me?
cv::Mat image;
while (image.empty())
{
image = cv::imread("capture.jpg",1);
}
cv::imwrite("result.jpg",image);
`

In Python the Mat of C++ becomes a numpy array and hence the image manipulation becomes as simple as accessing a multi dimensional array. However the methods name are same in both C++ and Python.
import cv2 #importing opencv module
img = cv2.imread("capture.jpg", 1) #Reading the whole image
cv2.imwrite("result.jpg", img) # Creating a new image and copying the contents of img to it
EDIT: If you want to write the contents as soon as the image file is being generated then you can use os.path.isfile() which return a bool value depending upon the presence of a file in the given directory.
import cv2
import os.path
while not os.path.isfile("capture.jpg"):
#ignore if no such file is present.
pass
img = cv2.imread("capture.jpg", 0)
cv2.imwrite("result.jpg", img)
You can also refer to docs for detailed implementation of each method and basic image operations.

Related

Returning Pixel Value as "None"

I have the following line of code:
img = cv.imread("c:/users/admin/downloads/sack.jpg", 1)
It is not reading anything into img. img is showing None. sack.jpg exists, and is an image file.
import os
import cv2
image_path = r"c:/users/admin/downloads/sack.jpg"
assert os.path.isfile(image_path)
img = cv2.imread(image_path, 1)
Either the assert will fail, or the read will succeed, or the file is not a valid image.
Notice the r preceding the path.
Also notice cv2, not cv.
EDITED
This worked for me on WINDOWS:
import cv2
path = r'c:/users/admin/downloads/sack.jpg'
img = cv2.imread(path)
cv2.imshow('imgTitle',img)
cv2.waitKey()
you can check how cv2.imread works here.
Note that:
It's (cv2) not cv.
Add cv.waitKey() so your image won't open and close very fast.
Anyway using the manual path writing is not very practical in the
real time applications, insted of that you can try using libraries
like os and pathlib, it's very recommended too.

OpenCV python canny Required argument 'threshold2' (pos 4) not found

I am trying to isolate text from an image with openCV before sending it to tesseract4 engine to maximize results.
I found this interesting post and I decided to copy the source and try by mysdelf
However I am getting issue with the first call to OpenCV
To reproduce:
Simply copy the code from the gist
launch command script.py /path/to/image.jpg
I am getting issue:
Required argument 'threshold2' (pos 4) not found
Do you maybe have an idea of what does it means.
I am a javascript, java and bash script developer but not python...
In a simple version:
import glob
import os
import random
import sys
import random
import math
import json
from collections import defaultdict
import cv2
from PIL import Image, ImageDraw
import numpy as np
from scipy.ndimage.filters import rank_filter
if __name__ == '__main__':
if len(sys.argv) == 2 and '*' in sys.argv[1]:
files = glob.glob(sys.argv[1])
random.shuffle(files)
else:
files = sys.argv[1:]
for path in files:
out_path = path.replace('.jpg', '.crop.png')
if os.path.exists(out_path): continue
orig_im = Image.open(path)
edges = cv2.Canny(np.asarray(orig_im), 100, 200)
Thanks in advance for your help
Edit: okay so this answer is apparently wrong, as I tried to send my own 16-bit int image into the function and couldn't reproduce the results.
Edit2: So I can reproduce the error with the following:
from PIL import Image
import numpy as np
import cv2
orig_im = Image.open('opencv-logo2.png')
threshold1 = 50
threshold2 = 150
edges = cv2.Canny(orig_im, 50, 100)
TypeError: Required argument 'threshold2' (pos 4) not found
So if the image was not cast to an array, i.e., the Image class was passed in, I get the error. The PIL Image class is a class with a lot of things other than the image data associated to it, so casting to a np.array is necessary to pass into functions. But if it was properly cast, everything runs swell for me.
In a chat with Dan MaĊĦek, my idea below is a bit incorrect. It is true that the newer Canny() method needs 16-bit images, but the bindings don't look into the actual numpy dtype to see what bit-depth it is to decide which function call to use. Plus, if you try to actually send a uint16 image in, you get a different error:
edges = cv2.Canny(np.array([[0, 1234], [1234, 2345]], dtype=np.uint16), 50, 100)
error: (-215) depth == CV_8U in function Canny
So the answer I originally gave (below) is not the total culprit. Perhaps you accidentally removed the np.array() casting of the orig_im and got that error, or, something else weird is going on.
Original (wrong) answer
In OpenCV 3.2.0, a new method for Canny() was introduced to allow users to specify their own gradient image. In the original implementation, Canny() would use the Sobel() operator for calculating the gradients, but now you could calculate say the Scharr() derivatives and pass those into Canny() instead. So that's pretty cool. But what does this have to do with your problem?
The Canny() method is overloaded. And it decides which function you want to use based on the arguments you send in. The original call for Canny() with the required arguments looks like
cv2.Canny(image, threshold1, threshold2)
but the new overloaded method looks like
cv2.Canny(grad_x, grad_y, threshold1, threshold2)
Now, there was a hint in your error message:
Required argument 'threshold2' (pos 4) not found
Which one of these calls had threshold2 in position 4? The newer method call! So why was that being called if you only passed three args? Note that you were getting the error if you used a PIL image, but not if you used a numpy image. So what else made it assume you were using the new call?
If you check the OpenCV 3.3.0 Canny() docs, you'll see that the original Canny() call requires an 8-bit input image for the first positional argument, whereas the new Canny() call requires a 16-bit x derivative of input image (CV_16SC1 or CV_16SC3) for the first positional argument.
Putting two and two together, PIL was giving you a 16-bit input image, so OpenCV thought you were trying to call the new method.
So the solution here, if you wanted to continue using PIL, is to convert your image to an 8-bit representation. Canny() needs a single-channel (i.e. grayscale) image to run, first off. So you'll need to make sure the image is single-channel first, and then scale it and change the numpy dtype. I believe PIL will read a grayscale image as single channel (OpenCV by default reads all images as three-channel unless you tell it otherwise).
If the image is 16-bit, then the conversion is easy with numpy:
img = (img/256).astype('uint8')
This assumes img is a numpy array, so you would need to cast the PIL image to ndarray first with np.array() or np.asarray().
And then you should be able to run Canny() with the original function call.
The issue was coming from an incompatibility between interfaces used and openCV version.
I was using openCV 3.3 so the correct way to call it is:
orig_im = cv2.imread(path)
edges = cv2.Canny(orig_im, 100, 200)

Trying to read numpy array into opencv - cv2.imdecode returns empty argument

Just getting back into coding after a few years out. Trying to write a piece of code that can go through a folder with .fits files, read out the image data, convert them to an array, read them into opencv, then perform edge detection on them. I can get it working fine with .png files as I don't have to play with arrays. I've done a lot of reading about, and that's enabled me to get to this point. Problem is, img is currently being returned empty, which causes everything else to freak. Any ideas please? Any help would be gratefully received!
#import packages
import cv2
from matplotlim import pyplot as plt
import os
from astropy.io import fits
from skimage import img_as_uint
import numpy as np
#create array with filenames
data = []
for root, dirs, files in os.walk(r'/Users/hannah/Desktop/firefountain-testset'):
for file in files:
if file.endswith('.fits'):
data.append(file)
#start my loop through the folder
for i in data:
fn = i
#read fits image data
hdulist = fits.open(fn)
img_data = hdulist[1].data
#put fits data into array with dtype set as original
imgraw=np.array(img_data, dtype = np.uint8)
#convert to uint16
img = img_as_uint(imgraw)
#crop to area of interest then add into array - possibly don't need second line
imgcrop = img[210:255,227:277]
imgcroparr = np.array(imgcrop)
#attempt to read into cv2 - this is where it loses the data
#all fine before this point I believe
imgfinal = cv2.imdecode(imgcroparr, 0,)
plt.imshow(imgfinal)
#imgfinal returns blank.
google drive with .fits files I'm using, plus .png to show what they should look like
Updated my code
for i in data:
fn = i
imgraw = fits.getdata(fn)
imgcrop = imgraw[210:255,227:277]
img = cv2.imdecode(imgcrop, 0,)
plt.imshow(img)
This opens the fits files no issue and imgcrop works as expected. cv2.imdecode(imgcrop, 0), however, throws up the following:
error: /Users/jhelmus/anaconda/conda-bld/work/opencv-2.4.8/modules/highgui/src/loadsave.cpp:307: error: (-215) buf.data && buf.isContinuous() in function imdecode_
Can't find anything on this error in this context online, getting more and more confused. It's probably something very silly and basic that I've forgotten to do, but I can't see it.

Using python to save a JPG image that was edited in the script

Referring to the answer to this question, I tried to save my own JPG image files, after some basic image processing. I've only applied a rotation and a shear. This is my code:
import numpy as np
import sys
from skimage import data, io, filter, color, exposure
import skimage.transform as tf
from skimage.transform import rotate, setup, AffineTransform
from PIL import Image
mypath = PATH_TO_FILENAME
readfile = FILENAME
img = color.rgb2gray(io.imread(mypath + readfile))
myimg = rotate(img, angle=10, order=2)
afine_tf = tf.AffineTransform(shear=0.1)
editedimg = tf.warp(myimg, afine_tf)
# IF I UNCOMMENT THE TWO LINES BELOW, I CAN SEE THE EDITED IMAGE AS EXPECTED
#io.imshow(editedimg)
#io.show()
saveimg= np.array(editedimg)
result = Image.fromarray((saveimg).astype(np.uint8))
newfile = "edited_" + readfile
result.save(path+newfile)
I know that the image processing was fine because if I display it before saving, it's just the original image with a bit of rotation and shearing, as expected. But I'm doing something wrong while saving it. I tried without the astype(np.uint8)) part but got an error. Then I removed some of the code from the link mentioned above because I guessed it was particularly for Fourier Transforms, since when I included some of their code, then I got an image that was all gray but with white lines in the direction of the shear I'd applied. But now the image that gets saved is just 2KB of nothing but blackness.
And when I tried something as simple as:
result = Image.fromarray(editedimg)
result.save(path+newfile)
then I got this error:
raise IOError("cannot write mode %s as JPEG" % im.mode)
IOError: cannot write mode F as JPEG
I don't really need to use PIL, if there's another way to simply save my image, I'm fine with that.
Look into the PIL fork, Pillow, is is not as outdated and what you should probably be using for this.
Also depending on your operating system you may need a few other libraries to compile PIL with JPEG support properly, see here
This may also help Says you need to convert your image to RGB mode before saving.
Image.open('old.jpeg').convert('RGB').save('new.jpeg')

How do I create an OpenCV image from the contents of a file?

Usually I would create an image in OpenCV as:
from cv2 import imread
img = imread("/home/nick/myfile.jpg")
But already have the contents of the file in another variable, so how to I create an OpenCV from this directly? e.g.
fc = open("/home/nick/myfile.jpg", "rb").read()
img = something(fc)
What is something? Is there an OpenCV or numpy function to do this?
cv2.imdecode() can do that in memory. and yes, it wants a numpy array as input

Categories