I am working on some code for my master thesis. There are two threads, one does cv2.VideoCapture(), sets the ready Event(), in the second thread while loop waits for the event to be set and then does some image processing. Typical producer, consumer problem.
The problem is, that I am trying to create "model" of the scene, where I would update pixels only in areas without red circle, which i am using as a marker to detect position of an object. I need to remember part of image behind the red marker and then update area everywhere else.
The problem is, that i need to mark the center of the red circle. I use the cv2.circle(). Black dot somehow gets in the model, even though I have never put it there. The cv2.putText() function has the same problem. The code looks like this.
if __name__ == "__main__":
ready = Event()
vs = VideoStream(0, ready).start()
v = Vision(vs.read())
cv2.imshow('firework', v.getImg())
while cv2.getWindowProperty('firework', cv2.WND_PROP_VISIBLE) >= 1:
# data acquisition
while not ready.isSet():
pass
img = vs.read()
ready.clear()
# image processing
v.updateImg(img)
v.detectRedMarker() # set cX, cY
mask = v.getROIMask(radius=100)
v.updateModel(mask) # circle mask, center cX, cY
# extras
img = v.putMarkerToImg(img)
cv2.imshow('firework', img)
if cv2.waitKey(1) == ord(' '):
break
vs.stop()
Methods in the Vision class...
def updateImg(self, img):
self.img = img
self.imgGray = cv2.cvtColor(self.img,cv2.COLOR_BGR2GRAY)
return
def getROIMask(self,radius):
mask = np.zeros((self.imgHeight, self.imgWidth),np.uint8)
cv2.circle(mask, (self.cX, self.cY), radius, 1, thickness=-1)
return mask
def updateModel(self,mask):
modelUpdate = cv2.bitwise_and(self.imgGray, cv2.bitwise_not(mask*255))
modelOld = cv2.bitwise_and(self.model, (mask*255))
self.model = cv2.add(modelOld,modelUpdate)
return
As you can see, I put the dot in the center of the red marker after i update the model and then read new image in the next iteration. Somehow the black dot gets into the model. Can anyone please suggest how does this happen?
Black dot marking the center of red circle somehow gets into the model
Related
I am taking a live image from a camera in Python and displaying it in an ImageView in my PyQt5 GUI, presenting it as a live feed.
Is is displaying fine, but I would like to draw a red crosshair on the center of the image to help the user know where the object of focus moved, relative to the center of the frame.
I tried drawing on it using "cv2.line(params)" but I do not see the lines. This is strange to me because in C++, when you draw on an image, it takes the mat and changes that mat in the code going forward. How can I display this on the UI window without having to make a separate call to cv2.imshow()?
This is the signal from the worker thread that changes the image, it emits an ndarray and a bool:
def pipeline_camera_acquire(self):
while True:
self.mutex.lock()
#get data and pass them from camera to img object
self.ximeaCam.get_image(self.img)
#get data from camera as numpy array
data_pic = self.img.get_image_data_numpy()
#Edits
cv2.line(data_pic, (-10,0), (10,0), (0,0,255), 1)
cv2.line(data_pic, (0,10), (0,-10), (0,0,255), 1)
self.editedIMG = np.rot90(data_pic, 3)
self.mutex.unlock()
#send signal to update GUI
self.imageChanged.emit(self.editedIMG, False)
I don't think that it isn't drawing the line, I think it just is drawing it out of the visible area. (0,0) is the upper right hand corner of the image, so (0,10),(0,-10), would be a thin line right at the edge of the image.
If you are trying to draw in the center then you should calculate it from the center of the numpy array.
For example:
x, y = data_pic.shape[0]//2, data_pic.shape[1]//2
cv2.line(data_pic, (x-10,y), (x+10,y), (0,0,255), 1)
cv2.line(data_pic, (x, y-10), (x, y+10), (0,0,255), 1)
That should draw the
I don't know where to start:
from PIL import Image
im1 = Image.open('C:/background.png') # size = 1065x460px
I need to load an image that would be the "background", and on this image I will place a series of circles when a condition is met.
And when another condition is met, delete or update only the previous circle (the background must always remain) and place the new circle
I just edited the post:
Now I have an image that will be the background (that I will never erase)
and on the other hand I have the circles, which will be generated by graph.DrawCircle and my question, is there a way to update and delete these circles, that is, when I place the 2nd circle the 1st is deleted.
layout = [sg.Graph(canvas_size=(1065, 460), graph_bottom_left=(0, 0),
graph_top_right=(1065, 460), key="-GRAPH-")]
graph = window.Element("-GRAPH-")
def circle_position(x,y,r):
graph.DrawCircle((x,y), r, line_color='red')
before drawing a circle I have to erase all circles (but not the background) :
elif (event =="Display Error Code") or (event == 'Submit'):
# erasing all the circles------before drawing the new circle
circle_position(324,257,16)
if (values[0] == "1002") : # 2nd circle
# erasing all the circles------before drawing the new circle
circle_position(342,303,16)
Thanks again
I'm building a shape analysis algorithm and one of the attributes we would like to add is whether the shape is open or closed. For example, the left circle is closed, the middle circle is open and the right circle is more open.
I tried to do it via the contours but I search for a more robust (and hopefully easy) way to achieve it. I know it can be solved with ANN but I don't want to go in that direction.
(I'm working with Python/OpenCV 4)
Any ideas?
There is a great way to do it using ImageDraw.floodfill function.
Attached is a working code:
from PIL import Image, ImageDraw
def openOrClose(img2):
isCLosed = False
img = cv2.cvtColor(img2, cv2.COLOR_GRAY2BGR)
target_pixel = (0,0) #Corner of the image
target_color = (255,255,0) #Yellow
im_pil = Image.fromarray(img)
ImageDraw.floodfill(im_pil,target_pixel,target_color)
im = np.asarray(im_pil)
count =0
for i in range(im.shape[0]):
for j in range(im.shape[1]):
if ((im[i][j] == [255,255,255]).all() == True):
count+=1
if count != 0:
isCLosed = True
return isCLosed
and this is the result:
If the object is the only thing in the array you are analyzing you could flood fill from any of the corners. If the area occupied by your flood fill value is less than the image area with the drawing's area subtracted it would be a closed object.
How can I highlight part of image? (Location defined as tuple of 4 numbers). You can imagine it like I have image of pc motherboard, and I need to highlight for example part where CPU Socket is located.
Note that for Python 3, you need to use the pillow fork of PIL, which is a mostly backwards compatible fork of the original module but, unlike it, is currently actively being maintained.
Here's some sample code that shows how to do it using the PIL.ImageEnhance.Brightness class.
Doing what you want requires multiple steps:
The portion to be highlighted is cut out of — or cropped from — the image.
An instance of the Brightness class is created from this cropped image.
The cropped image is the lightened by calling the enhance() method of the Brightness instance.
The cropped and now lightened image is pasted back into the location it came from.
To make doing them all easier to repeat, below is a function named highlight_area() to perform them.
Note that I've also added a bonus feature that will optionally outline the highlighted region with a colored border — which you can of course remove if you don't need or want it.
from PIL import Image, ImageColor, ImageDraw, ImageEnhance
def highlight_area(img, region, factor, outline_color=None, outline_width=1):
""" Highlight specified rectangular region of image by `factor` with an
optional colored boarder drawn around its edges and return the result.
"""
img = img.copy() # Avoid changing original image.
img_crop = img.crop(region)
brightner = ImageEnhance.Brightness(img_crop)
img_crop = brightner.enhance(factor)
img.paste(img_crop, region)
# Optionally draw a colored outline around the edge of the rectangular region.
if outline_color:
draw = ImageDraw.Draw(img) # Create a drawing context.
left, upper, right, lower = region # Get bounds.
coords = [(left, upper), (right, upper), (right, lower), (left, lower),
(left, upper)]
draw.line(coords, fill=outline_color, width=outline_width)
return img
if __name__ == '__main__':
img = Image.open('motherboard.jpg')
red = ImageColor.getrgb('red')
cpu_socket_region = 110, 67, 274, 295
img2 = highlight_area(img, cpu_socket_region, 2.5, outline_color=red, outline_width=2)
img2.save('motherboard_with_cpu_socket_highlighted.jpg')
img2.show() # Display the result.
Here's an example of using the function. The original image is shown on the left opposite the one resulting from calling the function on it with the values shown in the sample code.
So the popular approach to lane detection using computer vision is to perform these 5 steps:
Convert the image to grayscale, smooth the image by gaussian
function
Use canny edge function to detect edges (obviously right? )
Mark the region of interest ROI
Use hough transform fucntion to detect straight lines and have line function to draw them.
That's what my approach.
But the point here is we usually need to manually select the ROI. In most case when apply to dash camera on a car, it's ok since the view does not change much.
But my situation is different, I want to detect road lanes based on traffic surveillance cameras, and of course there are many of them. Each camera has its own view, so I think that there must be a way to automatically separate the road and non-road areas.
My question is how to detect the ROI automatically?
My idea here is that the road area will have lots of pixel movements and the non-road area will not. From that idea we could automatically detect the ROI.
I have manage to use opencv to extract the background (background subtracted) from this video (https://youtu.be/bv3NEzjb5sU) using openCV and subtractBackgroundMOG2 function.
The code about canny edge and hough transform is basically ok after we have the ROI. This below is the code to train and extract the background. I though we could modify it to give the region mask or something that can use as ROI for later steps.
Thank you.
import cv2
from pathlib import Path
def bg_train(video_source, number_of_run, number_of_frames):
cap = cv2.VideoCapture(video_source)
fgbg = cv2.createBackgroundSubtractorMOG2(detectShadows=True)
frame_number = -1
default_background = Path("default_background.png")
# the number of loop that will run to create a better background
i = 0
# check the file if it's already exist
if default_background.is_file():
i = 1
default_background = "default_background.png"
else:
default_background = None
i = 0
while i < number_of_run:
# Capture next frame and show in window
ret, frame = cap.read()
if not ret:
print("frame capture failed or not :)")
break
cv2.imshow("training_original", frame)
# subtract foreground and show in new window
background_read = cv2.imread(default_background)
fg = fgbg.apply(frame, background_read, -1)
fg_mask = filter_mask(fg)
cv2.imshow('Training_FG', fg_mask)
# subtract background and show in new window
bg = fgbg.getBackgroundImage(fg_mask)
cv2.imshow('Training_background', bg)
print(i, frame_number, bg.shape[0], bg.shape[1], bg.shape[2])
# Counting frame and save the final background after training
frame_number += 1
if frame_number == number_of_frames and i < number_of_run - 1:
i += 1
cv2.imwrite("default_background.png", bg)
cap.release()
cv2.destroyAllWindows()
cap = cv2.VideoCapture(video_source)
frame_number = -1
elif frame_number == number_of_frames and i == number_of_run - 1:
i += 1
cv2.imwrite("background_final.png", bg)
cv2.imshow("final background", bg)
return 1, bg
k = cv2.waitKey(1) & 0xff
if k == 27:
print("exit by user...")
return 0, None
cap.release()
cv2.destroyAllWindows()
def main():
video_source = "highway-30s.mp4"
check, background_after = bg_train(video_source, 2, 500)
if check == 0:
return 0
elif check == 1:
cv2.imshow("the background, press ESC to close window", background_after)
c = cv2.waitKey(0)
if c == 27:
cv2.destroyAllWindows()
if __name__ == '__main__':
main()
You could train the algorithm to pick the ROI, over an initial amount of time, by tracking movement in the viewport over a series of frames.
Filter out movements and create lines/vectors representing their direction. Once you have enough of these samples you can figure out the best ROI by using a bounding box which encapsulates these vectors.