I am trying to crop an avatar and place it in a given location in another image using python pil.
Here is the output of what I have so far:
And here is the code:
from PIL import Image
from PIL import ImageFont
from PIL import ImageDraw
import textwrap
text = "Creating Twitter Cards dynamically with Python"
background_image = "data/obi-pvc.png" # this is the background
avatar = Image.open("data/avatar.png")
font = "data/fonts/AllertaStencil-Regular.ttf"
background = Image.open(background_image)
background_width, background_height = background.size
avatar.convert('RGBA')
## DO NOT change below this line!!
save_name = f"{text.lower().replace(' ', '_')}.png"
#textwrapped = textwrap.wrap(text, width=text_wrap_width)
# crop avatar
width, height = avatar.size
x = (width - height)//2
avatar_cropped = avatar.crop((x, 0, x+height, height))
width_cr, height_cr = avatar_cropped.size
# create grayscale image with white circle (255) on black background (0)
mask = Image.new('L', avatar_cropped.size)
mask_draw = ImageDraw.Draw(mask)
width, height = avatar_cropped.size
mask_draw.ellipse((0, 0, width, height), fill=255)
# add mask as alpha channel
avatar_cropped.putalpha(mask)
draw = ImageDraw.Draw(background)
font = ImageFont.truetype(font, font_size)
draw.text((offset,margin), '\n'.join(textwrapped), font=font, fill=color)
x, y = avatar_cropped.size
margin = 40
# left top
position_tl = (0 + margin, 0 + margin)
position_tr = (x - margin - width_cr, 0 + margin)
position_bl = (0 + margin, y - margin - height_cr)
position_br = (x - margin - width_cr, y - margin - height_cr)
background.paste(avatar_cropped, position)
background.save(f"data/output/{save_name}")
display(background)
The avatar should fit within the circle. I can't seem to really figure out how to apply the positioning. Thanks
Here is the avatar:
I was trying to predict defects on a metal plate using yolov5 pre-trained weights.it was throwing this error:
**
File "C:\Users\acer.spyder-py3\metallic surface defect detection\untitled3.py", line 59, in post_process
if confidence >= CONFIDENCE_THRESHOLD:
ValueError: The truth value of an array with more than one element is ambiguous. Use a.any() or a.all()
**
import cv2
import numpy as np
# Constants.
INPUT_WIDTH = 640
INPUT_HEIGHT = 640
SCORE_THRESHOLD = 0.5
NMS_THRESHOLD = 0.45
CONFIDENCE_THRESHOLD = 0.45
# Text parameters.
FONT_FACE = cv2.FONT_HERSHEY_SIMPLEX
FONT_SCALE = 0.7
THICKNESS = 1
# Colors.
BLACK = (0,0,0)
BLUE = (255,178,50)
YELLOW = (0,255,255)
def draw_label(im, label, x, y):
"""Draw text onto image at location."""
# Get text size.
text_size = cv2.getTextSize(label, FONT_FACE, FONT_SCALE, THICKNESS)
dim, baseline = text_size[0], text_size[1]
# Use text size to create a BLACK rectangle.
cv2.rectangle(im, (x,y), (x + dim[0], y + dim[1] + baseline), (0,0,0), cv2.FILLED);
# Display text inside the rectangle.
cv2.putText(im, label, (x, y + dim[1]), FONT_FACE, FONT_SCALE, YELLOW, THICKNESS, cv2.LINE_AA)
def pre_process(input_image, net):
# Create a 4D blob from a frame.
blob = cv2.dnn.blobFromImage(input_image, 1/255, (INPUT_WIDTH, INPUT_HEIGHT), [0,0,0], 1, crop=False)
# Sets the input to the network.
net.setInput(blob)
# Run the forward pass to get output of the output layers.
outputs = net.forward(net.getUnconnectedOutLayersNames())
return outputs
def post_process(input_image, outputs):
# Lists to hold respective values while unwrapping.
class_ids = []
confidences = []
boxes = []
# Rows.
rows = outputs[0].shape[1]
image_height, image_width = input_image.shape[:2]
# Resizing factor.
x_factor = image_width / INPUT_WIDTH
y_factor = image_height / INPUT_HEIGHT
# Iterate through detections.
for r in range(rows):
row = outputs[0][0][r]
confidence = row[4]
# Discard bad detections and continue.
if confidence >= CONFIDENCE_THRESHOLD:
classes_scores = row[5:]
# Get the index of max class score.
class_id = np.argmax(classes_scores)
# Continue if the class score is above threshold.
if (classes_scores[class_id] > SCORE_THRESHOLD):
confidences.append(confidence)
class_ids.append(class_id)
cx, cy, w, h = row[0], row[1], row[2], row[3]
left = int((cx - w/2) * x_factor)
top = int((cy - h/2) * y_factor)
width = int(w * x_factor)
height = int(h * y_factor)
box = np.array([left, top, width, height])
boxes.append(box)
# Perform non maximum suppression to eliminate redundant, overlapping boxes with lower confidences.
indices = cv2.dnn.NMSBoxes(boxes, confidences, CONFIDENCE_THRESHOLD, NMS_THRESHOLD)
for i in indices:
box = boxes[i]
left = box[0]
top = box[1]
width = box[2]
height = box[3]
# Draw bounding box.
cv2.rectangle(input_image, (left, top), (left + width, top + height), BLUE, 3*THICKNESS)
# Class label.
label = "{}:{:.2f}".format(classes[class_ids[i]], confidences[i])
# Draw label.
draw_label(input_image, label, left, top)
return input_image
if __name__ == '__main__':
# Load class names.
classesFile = "defects.names"
classes = None
with open(classesFile, 'rt') as f:
classes = f.read().rstrip('\n').split('\n')
# Load image.
frame = cv2.imread('img_02_3436787300_00007_jpg.rf.e9923d3a70d1aeb92e45896b9c12cfa3.jpg')
# Give the weight files to the model and load the network using them.
modelWeights = "models_train/best.onnx"
net = cv2.dnn.readNet(modelWeights)
# Process image.
detections = pre_process(frame, net)
img = post_process(frame.copy(), detections)
"""
Put efficiency information. The function getPerfProfile returns the overall time for inference(t)
and the timings for each of the layers(in layersTimes).
"""
t, _ = net.getPerfProfile()
label = 'Inference time: %.2f ms' % (t * 1000.0 / cv2.getTickFrequency())
print(label)
cv2.putText(img, label, (20, 40), FONT_FACE, FONT_SCALE, (0, 0, 255), THICKNESS, cv2.LINE_AA)
cv2.imshow('Output', img)
cv2.waitKey(0)
I have little bit idea of deploying models into commercial use. If you find any other errors also please inform me . thanks in advance
A simple search led me to this SO post, highlighting a common issue recently.
Following this blog got me close but I faced the issue above.
net.getUnconnectedOutLayers() returns an array of index values. The output layers are obtained from net.getLayerNames() based on these index values.
In the following case net.getUnconnectedOutLayers() returns:
array([200, 227, 254])
We get the output layers from output_layers = [layer_names[i - 1] for i in net.getUnconnectedOutLayers() which returns:
['yolo_82', 'yolo_94', 'yolo_106']
Code:
The following is the complete working code for OpenCV version 4.5.5 (CPU):
image = cv2.imread(os.path.join(path, 'horse.jpg'))
Width = image.shape[1]
Height = image.shape[0]
scale = 0.00392
classes = None
with open(os.path.join(path, 'coco.names'), 'r') as f:
classes = [line.strip() for line in f.readlines()]
COLORS = np.random.uniform(0, 255, size=(len(classes), 3))
net = cv2.dnn.readNet(os.path.join(path, 'yolov3.weights'), os.path.join(path, 'yolov3.cfg'))
blob = cv2.dnn.blobFromImage(image, scale, (416,416), (0,0,0), True, crop=False)
net.setInput(blob)
def get_output_layers(net):
layer_names = net.getLayerNames()
output_layers = [layer_names[i - 1] for i in net.getUnconnectedOutLayers()]
return output_layers
def draw_bounding_box(img, class_id, confidence, x, y, x_plus_w, y_plus_h):
label = str(classes[class_id])
color = COLORS[class_id]
img = cv2.rectangle(img, (x,y), (x_plus_w,y_plus_h), color, 2)
img = cv2.putText(img, label, (x-10,y-10), cv2.FONT_HERSHEY_SIMPLEX, 0.5, color, 2)
# run inference through the network
# and gather predictions from output layers
outs = net.forward(get_output_layers(net))
# initialization
class_ids = []
confidences = []
boxes = []
conf_threshold = 0.5
nms_threshold = 0.4
image2 = image.copy()
for out in outs:
for detection in out:
scores = detection[5:]
class_id = np.argmax(scores)
confidence = scores[class_id]
if confidence > 0.5:
center_x = int(detection[0] * Width)
center_y = int(detection[1] * Height)
w = int(detection[2] * Width)
h = int(detection[3] * Height)
x = center_x - w / 2
y = center_y - h / 2
class_ids.append(class_id)
confidences.append(float(confidence))
boxes.append([x, y, w, h])
# apply non-max suppression
indices = cv2.dnn.NMSBoxes(boxes, confidences, conf_threshold, nms_threshold)
for i in indices:
i = i # i[0]
box = boxes[i]
x = box[0]
y = box[1]
w = box[2]
h = box[3]
draw_bounding_box(image2, class_ids[i], confidences[i], round(x), round(y), round(x+w), round(y+h))
Result:
Sample output:
The problem may be related to incompatible version of your installed modules.
Download .pt model.
wget https://github.com/ultralytics/YOLOv5/releases/download/v6.1/YOLOv5s.pt
And export to ONNX using your machine:
git clone https://github.com/ultralytics/YOLOv5
cd YOLOv5
pip install -r requirements.txt
pip install onnx
python3 export.py --weights models/YOLOv5s.pt --include onnx
Use the new converted .onnx file can solve the problem.
I am struggling to find a way to get my program to change the image to grayscale after the user clicks on the original image. The curly brackets are where I believe my problem is.
import image
img = image.Image("nature.jpg")
win = image.ImageWin(img.getWidth(), img.getHeight())
img.draw(win)
img.setDelay(1,15)
if {}:
for row in range(img.getHeight()):
for col in range(img.getWidth()):
p = img.getPixel(col, row)
aver = (p.getRed() + p.getGreen() + p.getBlue())/3
newred = aver
newgreen = aver
newblue = aver
newpixel = image.Pixel(newred, newgreen, newblue)
img.setPixel(col, row, newpixel)
img.draw(win)
I need to remove all white-spaces from image but I don't know how to do it..
I am using trim functionality to trim white spaces from border but still white-spaces are present in middle of image I am attaching my original image from which I want to remove white-spaces
my code
from PIL import Image, ImageChops
import numpy
def trim(im):
bg = Image.new(im.mode, im.size, im.getpixel((0, 0)))
diff = ImageChops.difference(im, bg)
diff = ImageChops.add(diff, diff, 2.0, -100)
box = diff.getbbox()
if box:
im.crop(box).save("trim_pil.png")
im = Image.open("/home/einfochips/Documents/imagecomparsion/kroger_image_comparison/SnapshotImages/screenshot_Hide.png")
im = trim(im)
but this code only remove space from borders, I need to remove spaces from middle also. Please help if possible, it would be very good if I got all five images in different PNG file.
You could go the long way with a for loop
from PIL import Image, ImageChops
def getbox(im, color):
bg = Image.new(im.mode, im.size, color)
diff = ImageChops.difference(im, bg)
diff = ImageChops.add(diff, diff, 2.0, -100)
return diff.getbbox()
def split(im):
retur = []
emptyColor = im.getpixel((0, 0))
box = getbox(im, emptyColor)
width, height = im.size
pixels = im.getdata()
sub_start = 0
sub_width = 0
offset = box[1] * width
for x in range(width):
if pixels[x + offset] == emptyColor:
if sub_width > 0:
retur.append((sub_start, box[1], sub_width, box[3]))
sub_width = 0
sub_start = x + 1
else:
sub_width = x + 1
if sub_width > 0:
retur.append((sub_start, box[1], sub_width, box[3]))
return retur
This makes it easy to retrieve the crop boxes in the image like this:
im = Image.open("/home/einfochips/Documents/imagecomparsion/kroger_image_comparison/SnapshotImages/screenshot_Hide.png")
for idx, box in enumerate(split(im)):
im.crop(box).save("trim_{0}.png".format(idx))
If you already know the size of the images toy want to extract you could go with
def split(im, box):
retur = []
pixels = im.getdata()
emptyColor = pixels[0]
width, height = im.size;
y = 0;
while y < height - box[3]:
x = 0
y_step = 1
while x < width - box[2]:
x_step = 1
if pixels[y*width + x] != emptyColor:
retur.append((x, y, box[2] + x, box[3] + y))
y_step = box[3] + 1
x_step = box[2] + 1
x += x_step
y += y_step
return retur
Adding another parameter to the call
for idx, box in enumerate(split(im, (0, 0, 365, 150))):
im.crop(box).save("trim_{0}.png".format(idx))
Python noob needs some help guys! Can someone show me how to rewrite my code using loops? Tried some different syntaxes but did not seem to work!
img = cv2.imread("C://Users//user//Desktop//research//images//Underwater_Caustics//set1//set1_color_0001.png")
tile11=img[1:640, 1:360]
cv2.imwrite('tile11_underwater_caustic_set1_0001.png', tile11)
tile12=img[641:1280, 1:360]
cv2.imwrite('tile12_underwater_caustic_set1_0001.png', tile12)
tile13=img[1281:1920, 1:360]
cv2.imwrite('tile13_underwater_caustic_set1_0001.png', tile13)
tile21=img[1:640, 361:720]
cv2.imwrite('tile21_underwater_caustic_set1_0001.png', tile21)
tile22=img[641:1280, 361:720]
cv2.imwrite('tile22_underwater_caustic_set1_0001.png', tile22)
tile23=img[1281:1920, 361:720]
cv2.imwrite('tile23_underwater_caustic_set1_0001.png', tile23)
tile31=img[1:640, 721:1080]
cv2.imwrite('tile31_underwater_caustic_set1_0001.png', tile31)
tile32=img[641:1280, 721:1080]
cv2.imwrite('tile32_underwater_caustic_set1_0001.png', tile32)
tile33=img[1281:1920, 721:1080]
cv2.imwrite('tile33_underwater_caustic_set1_0001.png', tile33)
As you can see, the image will be cut into 9 equal-size pieces, how to write it using loops?
This won't produce the same result like your code, but will give you some ideas:
img = cv2.imread('sample.jpg')
numrows, numcols = 4, 4
height = int(img.shape[0] / numrows)
width = int(img.shape[1] / numcols)
for row in range(numrows):
for col in range(numcols):
y0 = row * height
y1 = y0 + height
x0 = col * width
x1 = x0 + width
cv2.imwrite('tile_%d%d.jpg' % (row, col), img[y0:y1, x0:x1])
I needed image tiling where last parts or edge tiles are required to be full tile images.
Here is the code I use:
import cv2
import math
import os
Path = "FullImage.tif";
filename, file_extension = os.path.splitext(Path)
image = cv2.imread(Path, 0)
tileSizeX = 256;
tileSizeY = 256;
numTilesX = math.ceil(image.shape[1]/tileSizeX)
numTilesY = math.ceil(image.shape[0]/tileSizeY)
makeLastPartFull = True; # in case you need even siez
for nTileX in range(numTilesX):
for nTileY in range(numTilesY):
startX = nTileX*tileSizeX
endX = startX + tileSizeX
startY = nTileY*tileSizeY
endY = startY + tileSizeY;
if(endY > image.shape[0]):
endY = image.shape[0]
if(endX > image.shape[1]):
endX = image.shape[1]
if( makeLastPartFull == True and (nTileX == numTilesX-1 or nTileY == numTilesY-1) ):
startX = endX - tileSizeX
startY = endY - tileSizeY
currentTile = image[startY:endY, startX:endX]
cv2.imwrite(filename + '_%d_%d' % (nTileY, nTileX) + file_extension, currentTile)
This is for massive image reconstruction using part of flowfree his code. By using a folder of sliced images in the same area the script is, you can rebuild the image. I hope this helps.
import cv2
import glob
import os
dir = "."
pathname = os.path.join(dir, "*" + ".png")
images = [cv2.imread(img) for img in glob.glob(pathname)]
img = images[0]
numrows, numcols = 1,1
height = int(img.shape[0] / numrows)
width = int(img.shape[1] / numcols)
for row in range(numrows):
for col in range(numcols):
y0 = row * height
y1 = y0 + height
x0 = col * width
x1 = x0 + width
cv2.imwrite('merged_img_%d%d.jpg' % (row, col), img[y0:y1, x0:x1])