Custom name for an opencv image (complex name) - python

hi I want to take a frame from the camera and save it in a folder 'images', I want the image to have name + current timestamp+.jpg , I'm getting error for typing it like this:
cv2.imwrite(os.path.join(path2 , rn), img)
where path2='images'
and rn=str(rightnow.strftime("%I:%M:%p"))
i get this error : could not find a writer for the specified extension in function 'cv::imwrite_'
how can I do it plz , I searched but didn't find an answer and I'm new to python, thanks in advance

The accepted answer is os specific.
What happens if you run the code in Windows?
Assume you have millions of code, are you going to change each slash / with \?
You should use os.path.sep instead of static slash declaration.
First, remove the : in strftime, you can use - or _ or nothing.
rn = str(rightnow.strftime("%I%M%p"))
Second, check whether the path exists, if it doesn't exist, create.
path3 = "".join([path2, os.path.sep, rn])
if not os.path.exists(path3):
os.mkdir(path3)
Third, create the image name
save = "".join([path3, os.path.sep, "image_name.png"])
If you are executing the statement inside the loop, you may use counter
counter += 1
save = "".join([path3, os.path.sep, "image_name{}.png".format(counter)])
Code:
import os
import cv2
from datetime import datetime
path2 = 'img2'
rightnow = datetime.now()
rn = str(rightnow.strftime("%I%M%p"))
img = cv2.imread("1.png")
path3 = "".join([path2, os.path.sep, rn])
if not os.path.exists(path3):
os.mkdir(path3)
save = "".join([path3, os.path.sep, "image_name.png"])
cv2.imwrite(save, img)

Try to change:
cv2.imwrite(os.path.join(path2 , rn), img)
to
cv2.imwrite(os.path.join(path2 , rn)+".jpg", img)

Related

Cannot iterate over a file?

I want to know how to apply a function over a file of images and save each of them in a separate file. For one image it works successfully, but i cannot apply it to all images.
import glob
images = glob.glob('/Desktop/Dataset/Images/*')
for img in images:
img = np.array(Image.open(img))
output = 'Desktop/Dataset/Output'
MyFn(img = img,saveFile = output)
You did not define the sv value in your 2nd code snippet.
As the image will be overwrite, try this code:
import glob
images = glob.glob('/Desktop/Dataset/Images/*')
i = 0
for img in images:
i += 1 #iteration to avoid overwrite
img = np.array(Image.open(img))
output = 'Desktop/Dataset/Output'
MyFn(img = img + str(i),saveFile = output)
try to use the library os directly with
import os
entries = os.listdir('image/')
this will return a list of all the file into your folder
This is because you are not setting the sv value in your loop. You should set it to a different value at each iteration in order for it to write to different files.

How to extract jpg EXIF metadata from a folder in chronological order

I am currently writing a script to extract EXIF GPS data from a folder of jpg images. I am using os.scandir to extract the entries from the folder but from my understanding os.scandir opens the files in an arbitrary way. I need the images to be opened in chronological order by filename. Below is my current code which works as intended however it does not open the images in the correct order. The files within my image folder are named chronologically like so: "IMG_0097, IMG_0098" etc.
#!/usr/bin/python
import os, exif, folium
def convert_lat(coordinates, ref):
latCoords = coordinates[0] + coordinates[1] / 60 + coordinates[2] / 3600
if ref == 'W' or ref == 'S':
latCoords = -latCoords
return latCoords
coordList=[]
map = folium.Map(location=[51.50197125069916, -0.14000860301423912], zoom_start = 16)
from exif import Image
with os.scandir('gps/') as entries:
try:
for entry in entries:
img_path = 'gps/'+entry.name
with open (img_path, 'rb') as src:
img = Image(src)
if img.has_exif:
latCoords = (convert_lat(img.gps_latitude, img.gps_latitude_ref))
longCoords = (convert_lat(img.gps_longitude, img.gps_longitude_ref))
coord = [latCoords, longCoords]
coordList.append(coord)
folium.Marker(coord, popup=str(coord)).add_to(map)
folium.PolyLine(coordList, color =" red", weight=2.5, opacity=1).add_to(map)
print(img_path)
print(coord)
else:
print (src.name,'has no EXIF information')
except:
print(img_path)
print("error occured")
map.save(outfile='/home/jamesdean/Desktop/Python scripts/map.html')
print ("Map generated successfully")
I would say ditch os.scandir and take advantage of more modern features the standard library has to offer:
from pathlib import Path
from operator import attrgetter
# assuming there is a folder named "gps" in the current working directory...
for path in sorted(Path("gps").glob("*.jpg"), key=attrgetter("stem")):
print(path) # do something with the current path
The from operator import attrgetter and key=attrgetter("stem") are a bit redundant, but I'm just being explicit about what attribute I would like to use for determining the sorted order. In this case, the "stem" attribute of a path refers to just the name of the file as a string. For example, if the current path has a filename (including extension) of "IMG_0097.jpg", then path.stem would be "IMG_0097". Like I said, the stem is a string, so your paths will be sorted in lexicographical order. You don't need to do any conversion to integers, because your filenames already include leading zeroes, so lexicographical ordering should work just fine.
You can sort a list using the built-in sorted function, Paul made an interesting point and simply sorting without any arguments will work just as fine:
a = ["IMG_0097.jpg", "IMG_0085.jpg", "IMG_0043.jpg", "IMG_0098.jpg", "IMG_0099.jpg", "IMG_0100.jpg"]
sorted_list = sorted(a)
print(sorted_list)
Output:
['IMG_0043.jpg', 'IMG_0085.jpg', 'IMG_0097.jpg', 'IMG_0098.jpg', 'IMG_0099.jpg', 'IMG_0100.jpg']
In your case you can do:
for entry in sorted(entries):

Trying to run a program in Pycharm

I have to test out a code in Pycharm (the bottom of the question), but I cannot figure out how to run it in Pycharm without getting this error:
usage: color.py [-h] -i IMAGE
color.py: error: the following arguments are required: -i/--image
I know that if I was using Idle I would have written this code:
/Users/syedrishad/Downloads/python-project-color-detection/color_detection.py -i
Users/syedrishad/Downloads/python-project-color-detection/colorpic.jpg
But I don't know how to run it on Pycharm
I use a mac and for some reason i always have to put the full path name or it doesn't work.(If that makes a difference)
This program makes it so if I double click on a part of the image, it shows the exact color name. All the color names are stored in this file:
/Users/syedrishad/Downloads/python-project-color-detection/colors.csv
The actual code is here:
import cv2
import numpy as np
import pandas as pd
import argparse
#Creating argument parser to take image path from command line
ap = argparse.ArgumentParser()
ap.add_argument('-i', '--image', required=True, help="Image Path")
args = vars(ap.parse_args())
img_path = args['image']
#Reading the image with opencv
img = cv2.imread(img_path)
#declaring global variables (are used later on)
clicked = False
r = g = b = xpos = ypos = 0
#Reading csv file with pandas and giving names to each column
index=["color","color_name","hex","R","G","B"]
csv = pd.read_csv('colors.csv', names=index, header=None)
#function to calculate minimum distance from all colors and get the most matching color
def getColorName(R,G,B):
minimum = 10000
for i in range(len(csv)):
d = abs(R- int(csv.loc[i,"R"])) + abs(G- int(csv.loc[i,"G"]))+ abs(B- int(csv.loc[i,"B"]))
if(d<=minimum):
minimum = d
cname = csv.loc[i,"color_name"]
return cname
#function to get x,y coordinates of mouse double click
def draw_function(event, x,y,flags,param):
if event == cv2.EVENT_LBUTTONDBLCLK:
global b,g,r,xpos,ypos, clicked
clicked = True
xpos = x
ypos = y
b,g,r = img[y,x]
b = int(b)
g = int(g)
r = int(r)
cv2.namedWindow('image')
cv2.setMouseCallback('image',draw_function)
while(1):
cv2.imshow("image",img)
if (clicked):
#cv2.rectangle(image, startpoint, endpoint, color, thickness)-1 fills entire rectangle
cv2.rectangle(img,(20,20), (750,60), (b,g,r), -1)
#Creating text string to display( Color name and RGB values )
text = getColorName(r,g,b) + ' R='+ str(r) + ' G='+ str(g) + ' B='+ str(b)
#cv2.putText(img,text,start,font(0-7),fontScale,color,thickness,lineType )
cv2.putText(img, text,(50,50),2,0.8,(255,255,255),2,cv2.LINE_AA)
#For very light colours we will display text in black colour
if(r+g+b>=600):
cv2.putText(img, text,(50,50),2,0.8,(0,0,0),2,cv2.LINE_AA)
clicked=False
#Break the loop when user hits 'esc' key
if cv2.waitKey(20) & 0xFF ==27:
break
cv2.destroyAllWindows()
If you know how to run, can you please tell me. I have been searching for an answer but come up empty-handed.
As #Yves Daoust mentioned you basically have two options:
A) Either change the code you are testing to provide the required argument or
B) Use Run->Run...->Edit Configurations... to provide the argument as you would from the command line.
Let's examine in more details the options you have:
A) The easiest way would be to provide the path to the image you want to open like this:
# replace img_path = args['image'] with
img_path = 'path/to/the/image'
which has the advantage of being extremely easy to get but it breaks the argparser functionality.
A more versatile solution would be to provide a default parameter and edit this one each time you want to open an image.
import argparse
# Add a global variable here. It will provide the argument if no other is given (via `Run->Run...->Edit Configurations...`)
IMAGE_PATH = 'path/to/image'
#Creating argument parser to take image path from command line
ap = argparse.ArgumentParser()
ap.add_argument('-i', '--image', required=True, help="Image Path", default=IMAGE_PATH)
which has the advantage of keeping the arg parse functionality intact if you are interested in this one.
B) This option means you provide the parameters yourself just like you would do in the console. The parameters are put in the Parameters: field.
For example you could pass:
--image="path/to/image"
PyCharm provides the option to Apply (button) the changes you inserted (which in this case would mean to keep the parameters stored for this script as long as the script will be in the memory).
Hope this clarify things a bit.
You have to go to Run > Run and then select the program you want to run. If it still gives an error, check the file path, otherwise, you have an error in your code. I hope that answers your question.

TypeError: an integer is required (got type str) in python

I am working with OpenCV ArUco in Python. I am trying to generate multiple codes of different directories. To generate it in a single time I am using this function in a loop. For example list1 =[1,2,3,4],comb = [50,100,250,1000],ids = [1,22,3,45]
def generator(bsize,comb,ids):
bitsize = [bsize]+['X']+[bsize]
bitz = ''.join(bitsize)
dicts = ['DICT']+[bitz]+[comb]
dictionary = '_'.join(dicts)
print(dictionary)
path = ['aruco']+[dictionary]
print(path)
path = '.'.join(path)
print(path)
aruco_dict = aruco.Dictionary_get(path)
img = aruco.drawMarker(aruco_dict, ids, bsize)
cv2.imshow('frame',img)
for i in range(0,7):
generator(list1[i],list2[i],list3[i])
the output of 'path' is:
aruco.DICT_4X4_1000
after that I am getting error:
line 35, in generator
aruco_dict = aruco.Dictionary_get(path)
TypeError: an integer is required (got type str)
How do I resolve this error. Please help
"aruco.DICT_4X4_1000", a string, is different from aruco.DICT_4X4_1000, an attribute in aruco.
If you want to programmatically access aruco's value for the attribute DICT_4X4_1000, you can use:
getattr(aruco, "DICT_4X4_1000")
So your code for getting path should be:
...
path = getattr(aruco, dictionary)
...
As I can see at http://www.philipzucker.com/aruco-in-opencv/, aruco.DICT_6X6_250 is real constant (int). In your can it is a string "aruco.DICT_6X6_250" and this is main reason of error. For clarification, just try the below 2 statements in place of path = '.'.join(path).
Valid
path = aruco.DICT_4X4_1000
Invalid
path = "aruco.DICT_4X4_1000"
You'll find, the 2nd one is responsible for error.
My suggestion to fix this kind of issue is to create any module named arcuo_constants.py and place the contents like below in that.
arcuo_constants.py
import cv2
import cv2.aruco as aruco
# define all possible constants here
ARUCO_CONSTANTS = {
"aruco.DICT_6X6_250": aruco.DICT_6X6_250,
"aruco.DICT_4X4_1000": aruco.DICT_4X4_1000
}
And finally in your code file, you can import and use those values as follows (Let suppose module file is in the same directory).
import aruco_constants
ARUCO_CONSTANTS = aruco_constants.ARUCO_CONSTANTS # A dictionary
# ...
# ...
path = '.'.join(path)
path = ARUCO_CONSTANTS[path]
aruco_dict = aruco.Dictionary_get(path)
# ...
# ...

Downloaded Images does not set as background always?

I am trying to download some images from MomentumDash (for educational purpose only).
I have written the following python code:
import urllib
import os
import random
#Chooses an image between 1 to 14
choice=random.randint(01,14)
print choice
#Downloads images
a=urllib.urlretrieve("https://momentumdash.com/backgrounds/"+"%02d" % (choice,)+".jpg", str(choice)+".jpg")
print a #Tells the image
#Getting the location of the saved image
cwd = os.getcwd()
random=random.choice(os.listdir(cwd))
file =cwd+ '\\' +random
#Making the image to desktop image
import ctypes
SPI_SETDESKWALLPAPER = 20
ctypes.windll.user32.SystemParametersInfoA(SPI_SETDESKWALLPAPER , 0, file, 3)
The thing is the probability of this progrm to set a image is 1/7 ish.
Most of the times it gives a black background screen.
Where am I wrong?
Try the following. This ensures that the directory listing is filtered to give you only jpg files. A random entry is taken from these. Also os.path.join() is used to safely join your path and name together.
import urllib
import os
import random
import ctypes
#Chooses an image between 1 to 14
choice = random.randint(1, 14)
#Downloads images
download_name = "{:02}.jpg".format(choice)
a = urllib.urlretrieve("https://momentumdash.com/backgrounds/{}".format(download_name), download_name)
#Getting the location of the saved image
cwd = os.getcwd()
#Filter the list to only give JPG image files
image_files = [f for f in os.listdir(cwd) if os.path.splitext(f)[1].lower() == ".jpg"]
random_image = random.choice(image_files)
full_path = os.path.join(cwd, random_image)
#Making the image to desktop image
SPI_SETDESKWALLPAPER = 20
ctypes.windll.user32.SystemParametersInfoA(SPI_SETDESKWALLPAPER , 0, full_path, 3)
The list of files is filtered by using Python's list comprehension feature. This is a way of building a new list from an existing item. In this case it uses the optional if statement to only include files in the new list which have an extension of .jpg.
Try the following:
import urllib
import os
import random
import ctypes
# Set up an output folder
out_folder = os.path.join(os.getcwd(), 'Backgrounds')
# Make it if it doesn't exist
if not os.path.isdir(out_folder):
os.mkdir(out_folder)
# Loop through all values between 1 and 15
for choice in range(1,15):
#Downloads images
a = urllib.urlretrieve("https://momentumdash.com/backgrounds/" + "%02d" % (choice,)+".jpg",
os.path.join(out_folder, "{}.jpg".format(choice))
)
selected_wallpaper = random.choice(os.listdir(out_folder))
#Making the image to desktop image
SPI_SETDESKWALLPAPER = 20
ctypes.windll.user32.SystemParametersInfoA(SPI_SETDESKWALLPAPER, 0, os.path.join(out_folder, selected_wallpaper), 3)
This creates a folder called Backgrounds in your current working directory, saves all the images there and then picks one at random.

Categories