Reading and detecting images, and save in folder - python

Firstly, I am simply reading images from the folder that contains different image formats. Secondly, the YOLO model detects the class, draws a rectangle and fills it with color only detected part, and saves it into another folder with the same name.
Second Case, If the model didn't detect anything in an image then it will save the same image with the same name but in a different folder.
My codebase is stuck on the first image and never moves on to the second image. I have no idea what is the problem happening.
Code
import torch
import cv2
from matplotlib import pyplot as plt
from utils.plots import Annotator, colors, save_one_box
import os
import glob
# Load Ours Custom Model
model = torch.hub.load('.', 'custom', path='/media/bmvc/CM_1/yolov5/runs/train/exp4/weights/last.pt', source='local')
# Files extension
img_Extension = ['jpg', 'jpeg', 'png']
# Load all testing images
my_path = "/home/bmvc/Documents/hide_info_test_dataset/testing_images/"
# Save images into array
files = []
[files.extend(glob.glob(my_path + '*.' + e)) for e in img_Extension]
# Iteration on all images
images = [cv2.imread(file) for file in files]
total_images = 1
# Taking only image name to save with save name
image_file_name = ''
for file in files:
for im in images:
detections = model(im[..., ::-1])
results = detections.pandas().xyxy[0].to_dict(orient="records")
if len(results) == 0:
cv2.imwrite(os.path.join("/home/bmvc/Documents/hide_info_test_dataset/detected/", file), im)
else:
for result in results:
print(result['class'])
con = result['confidence']
cs = result['class']
x1 = int(result['xmin'])
y1 = int(result['ymin'])
x2 = int(result['xmax'])
y2 = int(result['ymax'])
imagee = cv2.rectangle(im, (x1, y1), (x2, y2), (0, 255, 0), -1)
cv2.imwrite(os.path.join("/home/bmvc/Documents/hide_info_test_dataset/detected/", file), im)
total_images += 1

I have put a lot of loops that are completely useless for example reading different extension files, reading only images. I have improved the overall implementation and used only one loop to fix the above problem.
import torch
import cv2
from PIL import Image
from utils.plots import Annotator, colors, save_one_box
import os
import glob
import numpy as np
# Load Ours Custom Model
model = torch.hub.load('.', 'custom', path='/media/bmvc/CM_1/yolov5/runs/train/exp4/weights/last.pt', source='local')
# Files extension
img_Extension = ['jpg', 'jpeg', 'png']
# Load all testing images
my_path = "/home/bmvc/Documents/hide_info_test_dataset/testing_images/"
# Save images into array
files = []
[files.extend(glob.glob(my_path + '*.' + e)) for e in img_Extension]
# Iteration on all images
images = [cv2.imread(file) for file in files]
total_images = 1
# Taking only image name to save with save name
image_file_name = ''
for img in glob.glob(my_path + '*.*'):
img_bgr_rgb = cv2.imread(img)
file_Name = os.path.basename(img)
detections = model(img_bgr_rgb[:, :, ::-1])
results = detections.pandas().xyxy[0].to_dict(orient="records")
if len(results) == 0:
cv2.imwrite(os.path.join("/home/bmvc/Documents/hide_info_test_dataset/detected/", file_Name), img_bgr_rgb)
else:
for result in results:
print(result['class'])
con = result['confidence']
cs = result['class']
x1 = int(result['xmin'])
y1 = int(result['ymin'])
x2 = int(result['xmax'])
y2 = int(result['ymax'])
imagee = cv2.rectangle(img_bgr_rgb, (x1, y1), (x2, y2), (255, 87, 51), -1)
cv2.imwrite(os.path.join("/home/bmvc/Documents/hide_info_test_dataset/detected/", file_Name), img_bgr_rgb)

Related

OpenCV, Python, cv2 error: (-5:Bad argument) Empty training data was given.You'll need more than one sample to learn a model. in function 'train'

This is my code. I have a learning problem. Gives the error
error: (-5:Bad argument) Empty training data was given. You'll need more than one sample to learn a model. in function 'train'.
I can't solve this problem. I can't find an explanation on how to fix it? Where can I read about the solution to this problem? My pictures have size 200x200, format .pgm.
import os
import cv2
import numpy as np
def read_images(path, image_size):
names = []
training_images, training_labels = [], []
label = 0
for dirname, subdirnames, filenames in os.walk(path):
for subdirname in subdirnames:
names.append(subdirname)
subject_path = os.path.join(dirname, subdirname)
for filename in os.listdir(subject_path):
img = cv2.imread(os.path.join(subject_path, filename),
cv2.IMREAD_GRAYSCALE)
if img is None:
# The file cannot be loaded as an image.
# Skip it.
continue
img = cv2.resize(img, image_size)
training_images.append(img)
training_labels.append(label)
label += 1
training_images = np.asarray(training_images, np.uint8)
training_labels = np.asarray(training_labels, np.int32)
return names, training_images, training_labels
path_to_training_images = '/home/ace/OpenCV/cascades/A_M'# not properly. This is = '/home/ace/OpenCV/cascades/'
training_image_size = (200, 200)
names, training_images, training_labels = read_images(path_to_training_images, training_image_size)
model = cv2.face.EigenFaceRecognizer_create()
model.train(training_images, training_labels)
face_cascade = cv2.CascadeClassifier('/haarcascade_frontalface_default.xml')
camera = cv2.VideoCapture(2)
while (cv2.waitKey(1) == -1):
success, frame = camera.read()
if success:
faces = face_cascade.detectMultiScale(frame, 1.3, 5)
for (x, y, w, h) in faces:
cv2.rectangle(frame, (x, y), (x+w, y+h), (255, 0, 0), 2)
gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
roi_gray = gray[x:x+w, y:y+h]
if roi_gray.size == 0:
# The ROI is empty. Maybe the face is at the image edge.
# Skip it.
continue
roi_gray = cv2.resize(roi_gray, training_image_size)
label, confidence = model.predict(roi_gray)
text = '%s, confidence=%.2f' % (names[label], confidence)
cv2.putText(frame, text, (x, y - 20),
cv2.FONT_HERSHEY_SIMPLEX, 1, (255, 0, 0), 2)
cv2.imshow('Face Recognition', frame)
Although it seems a little bit odd that you use recursive walk-function and then seperately list the subdirectories, your read_images function works for me if I create a folder structure like this:
images/
- sub1/
- img1.png
- img2.png
- sub2/
- img3.png
- img4.png
The files are found and the return values are filled. Probably your folder structure differs from what your code expects.
You can try to debug your setup with some further print-statements like this:
def read_images(path, image_size):
names = []
training_images, training_labels = [], []
label = 0
for dirname, subdirnames, filenames in os.walk(path):
print(f"dirname={dirname}")
for subdirname in subdirnames:
print(f"- subdirname={subdirname}")
names.append(subdirname)
subject_path = os.path.join(dirname, subdirname)
for filename in os.listdir(subject_path):
print(f" - filename={filename}")
img = cv2.imread(os.path.join(subject_path, filename),
cv2.IMREAD_GRAYSCALE)
if img is None:
# The file cannot be loaded as an image.
# Skip it.
continue
img = cv2.resize(img, image_size)
training_images.append(img)
training_labels.append(label)
label += 1
training_images = np.asarray(training_images, np.uint8)
training_labels = np.asarray(training_labels, np.int32)
return names, training_images, training_labels
Please check the output of those prints and compare it with your folder structure. If this doesn't help, please share the debug output and your folder structure with us. Please don't share it as comment but by updating your question!

NotADirectoryError: [Errno 20] Not a directory: 'known_faces/.DS_Store'

How can I fix the following error:
NotADirectoryError: [Errno 20] Not a directory:
'known_faces/.DS_Store'
Code
import face_recognition
import os
import cv2
import numpy as np
KNOWN_FACES = "known_faces"
UNKNOWN_FACES = "unknown_faces"
TOLERANCE = 0.6
THICKNESS = 3
MODEL = "cnn"
known_faces = []
known_names = []
for name in os.listdir(KNOWN_FACES):
for filename in os.listdir(f"{KNOWN_FACES}/{name}"):
image = face_recognition.load_image_file(f"{KNOWN_FACES}/{name}/{filename}")
encoding = face_recognition.face_encodings(image)
known_faces.append(encoding)
known_names.append(name)
print("processing unknown_faces")
for filename in os.listdir(UNKNOWN_FACES):
print(filename)
image = face_recognition.load_image_file(f"{UNKNOWN_FACES}/{filename}")
locations = face_recognition.face_locations(image, model=MODEL)
encodings = face_recognition.face_encodings(image, locations)
image = cv2.cvtColor(image, cv2.COLOR_RGB2BGR)
for face_encoding, face_locations in zip(encodings, locations):
results = face_recognition.compare_faces(face_encoding, known_faces, TOLERANCE)
MATCH = None
if True in results:
match = known_names[results.index(True)]
print(f"Match found: {match}")
top_left = (face_location[3], face_location[0])
bot_right = (face_location[1], face_location[2])
color = [0, 255, 0]
cv2.rectangle(image, top_left, bot_right, color, THICKNESS)
top_left = (face_location[3], face_location[0])
bot_right = (face_location[1], face_location[2] + 22)
cv2.rectangle(image, top_left, bot_right, color, cv2.FILLED)
cv2.putText(image, math, (face_location[3]+10, face_location[2])+15, cv2.FONT_HERSEY_SIMPLEX, 0.5, (200,200,200), THICKNESS)
cv2.imshow(filename, image)
cv2.waitKey(10000)
os.listdir(KNOWN_FACES) returns all the files in the KNOWN_FACES directory. In your specific case also the .DS_Store file.
You can filter the results considering only directories and excluding files such as .DS_Store.
import os
for name in os.listdir(KNOWN_FACES):
dir_path = os.path.join(KNOWN_FACES, name)
# if it's a directory
if os.path.isdir(dir_path):
for filename in os.listdir(dir_path):
# if the file is a valid file (a better way could be to check your specific extension, e.g., png)
if not filename.startswith('.'):
filepath = os.path.join(dir_path, filename)
image = face_recognition.load_image_file(filepath)
There is a file in your "known_faces" directory named .DS_Store. Since you only want to look at directories in the "known_faces" directory, you need to remove that file.
As abc has pointed out, you may just want to check that you are looking in a directory by using os.path.isdir().

Save images having target objects from 1 folder to another after detecting target and non-target objects from the frames

Images from 1st folder are getting repeated along with images from 2nd folder while saving to the destination directory
I have made the code to identify target and non-target objects from images and save the images having my target object to a folder. Below is my code
def target_non_target(input_frames_folder,model_file,output):
if not os.path.exists(output):
os.makedirs(output,exist_ok=True)
count=0
folders = glob(input_frames_folder)
img_list = []
for folder in folders:
folder_name=os.path.basename(folder)
print(folder_name)
out_path = output +"\\" + folder_name
os.makedirs(out_path,exist_ok=True)
for f in glob(folder+"/*.jpg"):
img_list.append(f)
for i in range(len(img_list)):
v1=os.path.basename(img_list[i])
img_name = os.path.splitext(v1)[0]
image = cv2.imread(img_list[i])
orig = image.copy()
image = cv2.resize(image, (28, 28))
image = image.astype("float") / 255.0
image = img_to_array(image)
image = np.expand_dims(image, axis=0)
print("[INFO] loading network...")
model = load_model(model_file)
(non_target, target) = model.predict(image)[0]
if target > non_target:
label = "Target"
else:
label = "Non Target"
probab = target if target > non_target else non_target
label = "{}: {:.2f}%".format(label, probab * 100)
op = imutils.resize(orig, width=400)
cv2.putText(op, label, (10, 25), cv2.FONT_HERSHEY_SIMPLEX,0.7, (0, 255, 0), 2)
if target > non_target:
cv2.imwrite(out_path+"/"+"\\{}.jpg".format(img_name),orig)
cv2.waitKey(0)
#return target_op
frames_folder = ("C:\\Python36\\videos\\videos_new\\*")
model = ("C:\\Python35\\target_non_target\\target_non_target.model")
output_folder = ("C:\\Python35\\target_non_target\\Target_images_new")
target_check = target_non_target(frames_folder,model,output_folder)
Suppose there are 2 folders A and B in 2 different drives like Drive C and Drive D. Target images read from folder A of C Drive need to be saved in folder A of D drive. Target images from folder B of C Drive need to be saved in folder B of D Drive. This is working but images from folder A of D drive are getting repeated in folder B of D Drive which should not happen. Can someone guide me what changes shall be made for getting the desired results?
Of course Python offers all the tools you need. To copy files, you can use shutil.copy(). To find all JPEG files in the source directory, you can use glob.iglob().
import glob
import shutil
import os
src_dir = "your/source/dir"
dst_dir = "your/destination/dir"
for jpgfile in glob.iglob(os.path.join(src_dir, "*.jpg")):
shutil.copy(jpgfile, dst_dir)

"!empty() in function 'cv::CascadeClassifier::detectMultiScale'"

I am trying to work on a Face Recognition system in Python OpenCV but I keep getting the following error
"!empty() in function 'cv::CascadeClassifier::detectMultiScale'"
This is the code that I'm using:
import cv2
import os
import numpy as np
from PIL import Image
import pickle
BASE_DIR = os.path.dirname(os.path.abspath(__file__))
image_dir = os.path.join(BASE_DIR, "foto")
face_cascade = cv2.CascadeClassifier('haarcascade_frontalface_alt2.xml')
recognizer = cv2.face.LBPHFaceRecognizer_create()
current_id = 0
label_ids = {}
y_labels = []
x_train = []
for root, dirs, files in os.walk(image_dir):
for file in files:
if file.endswith("png") or file.endswith("jpg"):
path = os.path.join(root, file)
label = os.path.basename(root).replace(" ", "-").lower()
#print(label, path)
if not label in label_ids:
label_ids[label] = current_id
current_id += 1
id_ = label_ids[label]
#print(label_ids)
#y_labels.append(label) # some number
#x_train.append(path) # verify this image, turn into a NUMPY
arrray, GRAY
pil_image = Image.open(path).convert("L") # grayscale
size = (550, 550)
final_image = pil_image.resize(size, Image.ANTIALIAS)
image_array = np.array(final_image, "uint8")
#print(image_array)
faces = face_cascade.detectMultiScale(image_array, scaleFactor=1.5, minNeighbors=5)
for (x,y,w,h) in faces:
roi = image_array[y:y+h, x:x+w]
x_train.append(roi)
y_labels.append(id_)
#print(y_labels)
#print(x_train)
with open("pickles/face-labels.pickle", 'wb') as f:
pickle.dump(label_ids, f)
recognizer.train(x_train, np.array(y_labels))
recognizer.save("recognizers/face-trainner.yml")
What am I doing wrong?
You need to put the full path to the file.
Example:
face_cascade = cv2.CascadeClassifier('C:\\working_Dir\\data\\codes\\OpenCV\\classifiers\\haarcascade_frontalface_alt2.xml')
You can download these codes from the github Repo here : Face Detection with Python using OpenCV
I had the same issue, you need to add double slashes instead of single ones.
git clone https://github.com/opencv/opencv.git
faceCascade = cv2.CascadeClassifier('opencv/data/haarcascades/haarcascade_frontalface_default.xml')
you have to give full path of your haarcascade_frontalface_alt2.xml file
like this:-"C:\Python39\Lib\site-packages\cv2\data\haarcascade_frontalface_alt2.xml"
Xml file is missing.
Try to give full path directly like this.
face_cascade = cv2.CascadeClassifier('C:\opencv\sources\data\haarcascades\haarcascade_frontalface_default.xml')
more importantly the file should be in C Directory

How to change code to read and create multiple xml files?

I have this code that I am using to change the images I have saved in a folder called 'images' from .png to .xml with the additional information about them. When I run this code I only get the .xml file for image 000001 which I understand because I am having the code select that specific image. I am unsure how though to select multiple images in my file at a single time. I have images named from 000000 to 000355. Any advice would be great! really do not want to manually run the code 355 times!
import os
import cv2
from lxml import etree
import xml.etree.cElementTree as ET
def write_xml(folder, img, objects, tl, br, savedir):
if not os.path.isdir(savedir):
os.mkdir(savedir)
image = cv2.imread(img.path)
height, width, depth = image.shape
annotation = ET.Element('annotation')
ET.SubElement(annotation, 'folder').text = folder
ET.SubElement(annotation, 'filename').text = img.name
ET.SubElement(annotation, 'segmented').text = '0'
size = ET.SubElement(annotation, 'size')
ET.SubElement(size, 'width').text = str(width)
ET.SubElement(size, 'height').text = str(height)
ET.SubElement(size, 'depth').text = str(depth)
for obj, topl, botr in zip(objects, tl, br):
ob = ET.SubElement(annotation, 'object')
ET.SubElement(ob, 'name').text = obj
ET.SubElement(ob, 'pose').text = 'Unspecified'
ET.SubElement(ob, 'truncated').text = '0'
ET.SubElement(ob, 'difficult').text = '0'
bbox = ET.SubElement(ob, 'bndbox')
ET.SubElement(bbox, 'xmin').text = str(topl[0])
ET.SubElement(bbox, 'ymin').text = str(topl[1])
ET.SubElement(bbox, 'xmax').text = str(botr[0])
ET.SubElement(bbox, 'ymax').text = str(botr[1])
xml_str = ET.tostring(annotation)
root = etree.fromstring(xml_str)
xml_str = etree.tostring(root, pretty_print=True)
save_path = os.path.join(savedir, img.name.replace('png', 'xml'))
with open(save_path, 'wb') as temp_xml:
temp_xml.write(xml_str)
if __name__ == '__main__':
"""
for testing
"""
folder = 'images'
img = [im for im in os.scandir('images') if '000001' in im.name][0]
objects = ['auv']
tl = [(10, 10)]
br = [(100, 100)]
savedir = 'annotations'
write_xml(folder, img, objects, tl, br, savedir)
The basic idea is to make loop going through each of your image files, and do what you did for a single image before for each:
for img in os.scandir('images'):
objects = ['auv']
tl = [(10, 10)]
br = [(100, 100)]
savedir = 'annotations'
write_xml(folder, img, objects, tl, br, savedir)
(You might need to change the expression for your list of images, as it might now include things you don't want to process.)

Categories