Drawing from one surface to another surface - python

import cairo
import math
w = 2000
h = 2000
surface = cairo.ImageSurface(cairo.FORMAT_ARGB32, w, h)
ctx = cairo.Context(surface)
ctx.scale(w, h)
surface_path = cairo.ImageSurface(cairo.FORMAT_ARGB32, w, h)
ctx_path = cairo.Context(surface_path)
ctx_path.scale(w, h)
surface_circle = cairo.ImageSurface(cairo.FORMAT_ARGB32, w, h)
ctx_circle = cairo.Context(surface_circle)
ctx_circle.scale(w, h)
""" Lots of function calls that draw paths to surface_path and circles to surface_circle """
ctx.set_source_surface(surface_path, 0, 0)
ctx.paint()
ctx.set_source_surface(surface_circle, 0, 0)
ctx.paint()
surface_path.write_to_png("example.png")
surface_circle.write_to_png("example2.png")
surface.write_to_png("result.png")
Imgur link to saved images
I am attempting to compile two surfaces (one with lines, one with circles) onto one separate surface, then save that to a file.
Despite following what the documentation suggests should work, the final image ends up blank. I also tried calling flush() on surface_path and surface_circle, but that seemed to do nothing.
How could I combine the image info in surface_circle (example2.png) on top of surface_path (example.png), then output it to a file?

Try calling ctx.identity_matrix() before your last few paint() calls.
As is right-now, thanks to your call to ctx.scale(w, h), you only get the top-left pixels of those other surfaces scaled up to fill all of the target surface.

Related

Group contours with the same y value

I have been following a tutorial about computer vision and doing a little project to read the time from a game. The game time is formatted h:m. So far I got the h and m figured out using findContours, but I'm having trouble isolating the colon as the character shape is not continuous. Because of this when I try to matchTemplate the code freaks out and starts to use the dot to match to all the other digits.
Are there ways to group the contours by X?
Here are simplified code to get the reference digits, the code to get digits from the screen is basically the same.
refCnts = cv2.findContours(ref.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
refCnts = imutils.grab_contours(refCnts)
refCnts = contours.sort_contours(refCnts, method="left-to-right")[0]
digits = {}
# loop over the OCR-A reference contours
for (i, c) in enumerate(refCnts):
# compute the bounding box for the digit, extract it, and resize
# it to a fixed size
(x, y, w, h) = cv2.boundingRect(c)
roi = ref[y:y + h, x:x + w]
roi = cv2.resize(roi, (10, 13))
digits[i] = roi
Im new to python and opencv. Apologies in advance if this is a dumb question.
Here is the reference image I'm using:
Here is the input image I'm trying to read:
Do you have to use findCountours? Because there are better suited methods for such problems. For instance, you can use template matching as shown below:
These are input, template (cut out from your reference image), and output images:
import cv2
import numpy as np
# Read the input image & convert to grayscale
input_rgb = cv2.imread('input.png')
input_gray = cv2.cvtColor(input_rgb, cv2.COLOR_BGR2GRAY)
# Read the template (Using 0 to read image in grayscale mode)
template = cv2.imread('template.png', 0)
# Perform template matching - more on this here: https://docs.opencv.org/4.0.1/df/dfb/group__imgproc__object.html#ga3a7850640f1fe1f58fe91a2d7583695d
res = cv2.matchTemplate(input_gray,template,cv2.TM_CCOEFF_NORMED)
# Store the coordinates of matched area
# found the threshold value of .56 using trial & error using the input image - might be different in your game
lc = np.where( res >= 0.56)
# Draw a rectangle around the matched region
# I used the width and height of the template image but in practice you need to use a better method to accomplish this
w, h = template.shape[::-1]
for pt in zip(*lc[::-1]):
cv2.rectangle(input_rgb, pt, (pt[0] + w, pt[1] + h), (0,255,255), 1)
# display output
cv2.imshow('Detected',input_rgb)
# cv2.imwrite('output.png', input_rgb)
# cv2.waitKey(0)
# cv2.destroyAllWindows()
You may also look into text detection & recognition using openCV.

image aling with cv2 instead of HOG

Hi I am working on facial recognition.
To increase performance I want to use facial alignment.
When I use the HOG face identifier, described e.g., by Adrian I get an aligned image out.
from imutils.face_utils import rect_to_bb
from dlib import get_frontal_face_detector
detector = dlib.get_frontal_face_detector()
shape_predictor = dlib.shape_predictor('/home/base/Documents/facial_landmarks/shape_predictor_5_face_landmarks.dat')
fa = face_utils.facealigner.FaceAligner(shape_predictor, desiredFaceWidth=112, desiredLeftEye=(0.3, 0.3))
img=cv2.imread(pathtoimage)
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
rects = detector(gray, 2)
for rect in rects:
(x, y, w, h) = rect_to_bb(rect)
faceAligned = fa.align(img, gray, rect)
However, I have to work on an embedded hardware and the HOG facial recognition is not fast enough. The best working is the cv2 lbpcascader.
With cv2 I also get the box of the found face, but using that works not.
faces_detected = face_cascade.detectMultiScale(img, scaleFactor=1.1, minNeighbors=4)
In other examples using the HOG, the coordinates are extracted from the HOG-rect with:
(x, y, w, h) = rect_to_bb(rect)
and then used with
aligned_face = fa.align(img, gray, dlib.rectangle(left = x, top=y, right=w, bottom=h))
The idea would be to exchange the x,y,w,h with the cv2 values. Unfortunately, that does not work as the two lines above result in a complete false alignment. In the first code example, the rect_to_bb function is included but not used.
I checked the values and they are somehow off:
224x224 the image
156 70 219 219 the cv2 values (slightly different of course)
165 101 193 193 the rect values with rect_to_bb
[(165, 101) (358, 294)] the rect values
I checked the rect_to_bb function, but this seems straight forward:
def rect_to_bb(rect):
# take a bounding predicted by dlib and convert it
# to the format (x, y, w, h) as we would normally do
# with OpenCV
x = rect.left()
y = rect.top()
w = rect.right() - x
h = rect.bottom() - y
# return a tuple of (x, y, w, h)
return (x, y, w, h)
While typing I got the answer... classic
the alignment function needs the bounding box marks slightly different.
It can be seen in the rect_to_bb() function.
def rect_to_bb(rect):
# take a bounding predicted by dlib and convert it
# to the format (x, y, w, h) as we would normally do
# with OpenCV
x = rect.left()
y = rect.top()
w = rect.right() - x
h = rect.bottom() - y
# return a tuple of (x, y, w, h)
return (x, y, w, h)
There the rect.right (w in cv2) and the rect.bottom (h in cv2) are subtracted with x and y. So in the alignment function you have to add the values, otherwise the image fed to the alignment function is much to small and out of shape. And this can also be the values from the cv2 detection.
aligned_face = fa.align(img, gray, dlib.rectangle(left = x, top=y, right=w+x, bottom=h+y))
Keep healthy

Blur Detection of image using OpenCV

I am working on the blur detection of images. I have used the variance of the Laplacian method in OpenCV.
img = cv2.imread(imgPath)
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
value = cv2.Laplacian(gray, cv2.CV_64F).var()
The function failed in some cases like pixelated blurriness. It shows a higher value for those blur images than the actual clear images. Is there any better approach that detects Pixelated as well as motion blurriness?
Sample images:
This image is much clearer but showing value of 266.79
Where as this image showing the value of 446.51 .
Also this image seems to be much clearer but showing value only 38.96
I need to classify 1st and 3rd one as not blur whereas the second one as a blur.
I may be late to answer this one, but here is one potential approach.
The blur_detector library in pypi can be used to identify regions in an image which are sharp vs blurry. Here is the paper on which the library is created: https://arxiv.org/pdf/1703.07478.pdf
The way this library operates is that it looks at every pixel in the image at multiple scales and performs the discrete cosine transform at each scale. These DCT coefficients are then filtered such that we only use the high frequency coefficients. All the high frequency DCT coefficients at multiple scales are then fused together and sorted to form the multiscale-fused and sorted high-frequency transform coefficients
A subset of these sorted coefficients is selected. This is a tunable parameter and user can experiment with it based on the application. The output of the selected DCT coefficients is then sent through a max pooling to retain the maximum activation at multiple scales. This makes the algorithm quite robust to detect blurry areas in an image.
Here are the results that I see on the images that you have provided in the question:
Note: I have used a face detector from the default cascade_detectors in opencv to select a region of interest. the output of these two approaches (spatial blur detection + face detection) can be used to get the sharpness map in the image.
Here we can see that in the sharp images, the intensity of the pixels in the eyes region is very high, whereas for the blurry image, it is low.
You can threshold this to identify which images are sharp and which images are blurry.
Here is the code snippet which generated the above results:
pip install blur_detector
import blur_detector
import cv2
if __name__ == '__main__':
face_cascade = cv2.CascadeClassifier('cv2/data/haarcascade_frontalface_default.xml')
img = cv2.imread('1.png', 0)
blur_map1 = blur_detector.detectBlur(img, downsampling_factor=1, num_scales=3, scale_start=1)
faces = face_cascade.detectMultiScale(img, 1.1, 4)
for (x, y, w, h) in faces:
cv2.rectangle(blur_map1, (x, y), (x + w, y + h), (255, 0, 0), 2)
img = cv2.imread('2.png', 0)
blur_map2 = blur_detector.detectBlur(img, downsampling_factor=1, num_scales=3, scale_start=1)
faces = face_cascade.detectMultiScale(img, 1.1, 4)
for (x, y, w, h) in faces:
cv2.rectangle(blur_map2, (x, y), (x + w, y + h), (255, 0, 0), 2)
img = cv2.imread('3.png', 0)
blur_map3 = blur_detector.detectBlur(img, downsampling_factor=1, num_scales=3, scale_start=1)
faces = face_cascade.detectMultiScale(img, 1.1, 4)
for (x, y, w, h) in faces:
cv2.rectangle(blur_map3, (x, y), (x + w, y + h), (255, 0, 0), 2)
cv2.imshow('a', blur_map1)
cv2.imshow('b', blur_map2)
cv2.imshow('c', blur_map3)
cv2.waitKey(0)
To understand the details about the algorithm regarding the blur detector, please take a look at this github page: https://github.com/Utkarsh-Deshmukh/Spatially-Varying-Blur-Detection-python
You can try to define a threshold as float, so for every result falling under the threshold == blurry. But if the pixel images shows very high every time, even if not blurry, you could check for another value that is very high. Another way might be to detect focus of the picture.

Cairo shows just last drawing?

I create a widget that plots data and allows users a selections:
https://gobblin.se/u/kellogs/m/bildschirmfoto-vom-2013-11-12-13-23-54/
Sadly, in this screenshot should appear multiple selections (here red), but rendering n of this models doesn't work for some reason. I made sure, that the data is available and the rendering is called and works fine (right position and dimensions)
So my widget just creates a cairo surface that is used in a iteration of the following method to render the selections on top of the plotted data line:
def render_to(self, cairosurface):
'''external trigger to redraw widget on channel widget surface (only within plotarea!)'''
cr = cairosurface
pos_x=self.__getXPos()
w = self.__getWidth()
h = self.__getHeight()
eogclass=self.eogclassification.eogclass
#background
r,g,b=eogclass.color
alpha=0.9
color=(r,g,b,alpha)
cr.set_source_rgba(*color)
cr.rectangle(pos_x, 0, w, h)
cr.fill()
#label
label=eogclass.name
cr.set_source_rgb(*eogclass.text_color)
cr.set_font_size(13)
(x, y, width, height, dx, dy) = cr.text_extents(label)
cr.move_to(pos_x+w/2 - width/2, h/2) #center within our block
cr.text_path(label)
cr.clip()
cr.stroke()
cr.paint()
Can anybody give me a tip what might be the problem?
I'm not sure, but can this be a problem with compositing?

How to find the overlapping of an image on TkInter Canvas (Python)?

In Tkinter, when I create an image on a canvas and find the coordinates of it, it only returns two coordinates, so the find_overlapping method doesn't work with it (naturally). Is there an alternative?
You should be able to get the image's bounding box (bbox) by calling bbox = canvas.bbox(imageID). Then you can use canvas.find_overlapping(*bbox).
The coordinates it returns should be the coordinates of the top left corner of the image. So if the coordinates you got were (x, y), and your image object (assuming it's a PhotoImage) is img, then you can do:
w, h = img.width(), img.height()
find_overlapping(x, y, x + w, y + h)

Categories