How to read the window screen in python? - opencv

I want to read the window screen and display it by using the cv2.imshow() method.
Right now I am taking ScreenShot of the window and displaying that on the OpenCV window but it is also showing itself which I don't want.
which other approach should I adopt to get my result?
This is the code I am using right now.
while True:
img = screenshot()
img = np.array(img)
img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
cv2.imshow("Test", img)
libraries, I am using are:
pyautogui # for Screenshot()
cv2 # for imshow()
numpy # for array()
This is what I don't want to happen.
Saved screenshot
https://i.stack.imgur.com/7PaC1.jpg
Code is taking Screenshot of imshow window as well but also I do not want to close or minimize the imshow window.
Q. Is there any other method to achive what I want?

My personal preference would be to use cv2.imwrite instead of cv2.imshow. but if you requirement needs you to use imshow, you can check out these 2 methods and see which fits your requirements
Option 1: Destroy the window before you take the screenshot and then make it again, the code for that would look like:
while True:
img = screenshot()
img = np.array(img)
img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
cv2.imshow("Test", img)
cv2.destroyAllWindows()
I personally do not see a lot of merit to this method as it will majorly just keep creating and destroying windows
Option 2: OpenCV also allows you to move the window, you can use that to move the window before you are about to take the screenshot and then move it back in afterwards. The code for the same would look like:
while True:
# Just to check if img exists or not, needed for the 1st run of the loop
if 'img' in locals():
cv2.waitKey(100) #Without the delay, the imshow window will only keep flickering
cv2.moveWindow("Test", height, width)
img = screenshot()
img = np.array(img)
img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
height, width, ch = img.shape
cv2.imshow("Test", img)
cv2.moveWindow("Test", 0, 0)
The above 2 options were using the libraries that you already are using in your code. There is a third option too where you can minimize the window and then reopen it each time that you take a screenshot. You can find references to it over here, and here. And the code for the same should look like.
import ctypes
import win32gui
while True:
# Just to check if img exists or not,
# needed for the 1st run of the loop
if 'img' in locals():
cv2.waitKey(500) # Delay to stop the program from constantly opening and closing the window after itself
ctypes.windll.user32.ShowWindow(hwnd, 7)
# Window needs some time to be minimised
cv2.waitKey(500)
img = pyautogui.screenshot()
img = np.array(img)
img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
cv2.imshow("Test", img)
hwnd = win32gui.GetForegroundWindow()
ctypes.windll.user32.ShowWindow(hwnd, 9)

Related

OpenCV - Circle Detection Too Sensitive Even with Blur

Hi, just posting this on behalf of my 10yo son. He's working on a Python/OpenCV/GUI application and having some issues. Hoping someone might be able to point him in the right direction. Information as per below (maybe he needs to take a different approach?)
At the moment in my project I am having a problem with no errors. The only problem is the code isn't doing exactly what I want it to be. I can not tell if the blur is too strong, the blur is making the circle detection more sensitive or something else. My code is below.
I am trying to make the circle detection less sensitive by using a blur, however I can not tell what it's doing because there is no error.
What I want it to do is:
blur the image
ensure the circle detection is not to sensitive (not too many circles)
show the image unblurred and on the unblurred image show the circles from the blurred image
For an example, I should be able to detect moon craters.
import tkinter as tk
from tkinter import filedialog
from PIL import ImageTk, Image
import numpy as np
import cv2
root = tk.Tk()
root.title("Circle detecter")
root.geometry("1100x600")
root.iconbitmap('C:/Users/brett/')
def open():
global my_image
filename = filedialog.askopenfilename(initialdir="images", title="Select A File", filetypes=(("jpg files", "*.jpg"),("all files", "*.*")))
my_label.config(text=filename)
my_image = Image.open(filename)
tkimg = ImageTk.PhotoImage(my_image)
my_image_label.config(image=tkimg)
my_image_label.image = tkimg # save a reference of the image
def find_circles():
# convert PIL image to OpenCV image
circles_image = np.array(my_image.convert('RGB'))
gray_img = cv2.cvtColor(circles_image, cv2.COLOR_BGR2GRAY)
img = cv2.medianBlur(gray_img, 5)
circles = cv2.HoughCircles(img, cv2.HOUGH_GRADIENT, 1, 20,
param1=20, param2=60, minRadius=20, maxRadius=200)
if circles is not None:
circles = np.uint16(np.around(circles))
for i in circles[0]:
# draw the outer circle
cv2.circle(circles_image, (i[0],i[1]), i[2], (0,255,0), 2)
# draw the center of the circle
cv2.circle(circles_image, (i[0],i[1]), 2, (0,0,255), 3)
# convert OpenCV image back to PIL image
image = Image.fromarray(circles_image)
# update shown image
my_image_label.image.paste(image)
tk.Button(root, text="Load Image", command=open).pack()
tk.Button(root, text="Find circles", command=find_circles).pack()
# for the filename of selected image
my_label = tk.Label(root)
my_label.pack()
# for showing the selected image
my_image_label = tk.Label(root)
my_image_label.pack()
root.mainloop()

How to filter bigger font sizes of a text?

I've been writing a code to read a text, using opencv and tesseract on raspberry PI. It is working well, but I would like to filter only the title of the text, that is, differentiate the smallest characters from the biggest and extract only the biggest ones.
Is there any way to achieve this differentiation?
Here is the initial code:
import cv2
import pytesseract
cap = cv2.VideoCapture(0)
cap.set(3,640)
cap.set(4,480)
while True:
success, img = cap.read()
img = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
cv2.imshow("Video",img)
if cv2.waitKey(1) & 0xFF ==ord('q'):
cv2.imwrite("NewPicture.jpg",img)
break
text = pytesseract.image_to_string(img, config='--oem 3 --psm 11')
print(text)
Example image
A quick search of the pytesseract documentation shows that it has:
# Get verbose data including boxes, confidences, line and page numbers
print(pytesseract.image_to_data(Image.open('test.png')))
You may get quite a bit of data using this API and the filter the size of bounding boxes.

Is it possible to circle around the color spot on an image?

I'm doing an Image Processing Project. I'd like to circle around the yellow spot as follow.
How to know that position? I tried to find the value from image data (list), but I still don't know how to know that position and how to circle it.
Please help me.
Here is my sample code:
import cv2
import numpy as np
cap = cv2.imread("img.jpg")
cap = cv2.resize(cap, (500, 500))
hsv_frame = cv2.cvtColor(cap, cv2.COLOR_BGR2HSV)
# Yellow color
low_yellow = np.array([21, 39, 64])
high_yellow = np.array([40, 255, 255])
yellow_mask = cv2.inRange(hsv_frame, low_yellow, high_yellow)
yellow = cv2.bitwise_and(cap, cap, mask=yellow_mask)
cv2.imshow("Frame", cap)
test = cv2.imshow("Yellow", yellow)
cv2.imwrite("yellowSpot.jpg", yellow)
key = cv2.waitKey(0)
Here is my solution using GRIP and its auto-generated code (it's a great GUI for building image processing functions in a graphical, easy-to-experiment way):
My image processing "pipeline":
Image processing functions:
Blur (to remove all the little noise spots from the image, and preserve the yellow spot)
HSV threshold (to only show the YELLOW spot)
Find Blobs (to find the yellow spots and put a CIRCLE around it)
Here is the link to download the GRIP software
Here is a link to all my files (including the auto-generated Python image processing pipeline)

Simple blob detector does not detect blobs

I'm trying to use simple blob detector as described here, however a simplest possible code I've hacked does not seem to yield any results:
img = cv2.imread("detect.png")
detector = cv2.SimpleBlobDetector_create()
keypoints = detector.detect(img)
This code yields empty keypoints array:
[]
The image I'm trying to detects the blobs in is:
I would expect at least 2 blobs to be detected -- according to the documentation simpleblobdetector detects dark blobs and the image does contain 2 of those.
I know it is probably something embarassingly simple I'm missing here, but I cant seem to figure out what it is. My wild guess is, that it has to do something with the circularity of the blob, but trying all kinds of filter parameters I can't seem to figure out the right circularity parameters.
Update:
As per the comment below, where it has been suggested that I should invert my image, despite what the documentations suggests (unless I'm misreading it), I've tried to invert it and run the sample again:
img = cv2.imread("detect.png")
img = cv2.bitwise_not(img)
detector = cv2.SimpleBlobDetector_create()
keypoints = detector.detect(img)
However, as I suspected this gives the same results - no detections:
[]
The problem is the parameters :) and for the bottom blob is too close to the border...
You can take a look to the default parameters in this github link. And an interesting graph at the end of this link where you can check how the different parameters will influence the result.
Basically you can see that by default it is filtered by inertia, area and convexity. Now, if you remove the convexity and inertia filters, it will mark the top one. If you remove the area filter, still it will show only the top blob... The main issue with the bottom one is that it is too close to the border... and seems not to be a "blob" for the detector... but if add a small border to the image, it will appear. Here is the code I used for it:
import cv2
import numpy as np
img = cv2.imread('blob.png');
# create the small border around the image, just bottom
img=cv2.copyMakeBorder(img, top=0, bottom=1, left=0, right=0, borderType= cv2.BORDER_CONSTANT, value=[255,255,255] )
# create the params and deactivate the 3 filters
params = cv2.SimpleBlobDetector_Params()
params.filterByArea = False
params.filterByInertia = False
params.filterByConvexity = False
# detect the blobs
detector = cv2.SimpleBlobDetector_create(params)
keypoints = detector.detect(img)
# display them
img_with_keypoints = cv2.drawKeypoints(img, keypoints, outImage=np.array([]), color=(0, 0, 255),flags=cv2.DRAW_MATCHES_FLAGS_DRAW_RICH_KEYPOINTS)
cv2.imshow("Frame", img_with_keypoints)
cv2.waitKey(0)
cv2.destroyAllWindows()
and the resulting image:
And yes, you can achieve similar results without deactivating the filters but rather changing the parameters of it. For example, these parameters worked with exactly the same result:
params = cv2.SimpleBlobDetector_Params()
params.maxArea = 100000
params.minInertiaRatio = 0.05
params.minConvexity = .60
detector = cv2.SimpleBlobDetector_create(params)
It will heavily depend on the task at hand, and what are you looking to detect. And then play with the min/max values of each filter.

check pixel's transparency in OpenCV

How to check is pixel transparent in OpenCV? I have a png image with transparent portions and I want to convert rgb image to hsv and then change hue of pixels. I need that transparent pixels remain transparent after the conversion.
Any help please.
You may try GDAL. It is compatible with CV2
These links may be useful.
Reading Raster Data with GDAL
GDAL API Tutorial
import gdal
from gdalconst import *
import numpy as np
ds = gdal.Open('lena.jpg', GA_ReadOnly)
B = ds.GetRasterBand(1)
G = ds.GetRasterBand(2)
R = ds.GetRasterBand(3)
A = ds.GetRasterBand(4) // Alpha
height, width = B.shape
img = np.zeros(height, width, 3)
img[:, :, 0] = B
img[:, :, 1] = G
img[:, :, 2] = R
// Do something you want
ds.GetRasterBand(1).WriteArray(new_B)
ds.GetRasterBand(2).WriteArray(new_G)
ds.GetRasterBand(3).WriteArray(new_R)
// The forth band dose not need to be changed
// Close image, the changes is writen in the source file
ds = None
// Note that I did not test this code
OpenCV does not support transperancy in images. (before v2.4, I'm not sure about the latest version)
You can try the solution at http://blog.developer.stylight.de/2010/05/how-to-load-alpha-channel-pngs-with.html and rebuild OpenCV, or you can use something like ImageMagick to extract the alpha layer (forum link) as a separate image and load it.

Resources