How to detect free space between two detected windows - python-3.x

I used YOLOv3 to detect windows on the building. Each window shows with a bounding box around, also I extracted coordinates of each window [top_left, bottom_left, top_right, bottom_right]. now I want to find free space[wall] between all the windows. I put the coordinates of each window in a Dict.
when I set the values manually it works for each window for instance:
p1 = points_list[0][2] # top_left window1
p2 = points_list[1][1] # bottom_left window2
cv2.rectangle(img, p1, p2, (255, 0, 255), -1)
, but how can I make it automatically to find walls.
Here is my first output image, the detected wall shows by pink color.
here also I have added a sample of my code.
def bb_to_rect(x, y, w, h):
top_left = (x, y)
top_right = (x + w, y)
bottom_left = (x, y + h)
bottom_right = (x + w, y + h)
return top_left, bottom_left, top_right, bottom_right
def draw_bounding_box(img, font, boxes, confidences, colors):
indices = cv2.dnn.NMSBoxes(boxes, confidences, CONF_THRESHOLD, NMS_THRESHOLD)
points_list={}
count = 0
for i in range(len(boxes)):
if i in indices:
(x, y, w, h) = boxes[i]
label = "{}:{:.2f}%".format(classes[class_ids[i]], confidences[i] * 100)
color = colors[class_ids[i]]
cv2.rectangle(img, (x, y), (x + w, y + h), color, 2)
cv2.putText(img, str(i), (x, y), cv2.FONT_HERSHEY_TRIPLEX,
.5, (255, 255, 0), 1, cv2.LINE_AA)
top_left, bottom_left, top_right, bottom_right = bb_to_rect(x, y, w, h)
points_list[count] = [top_left, bottom_left, top_right, bottom_right]
count += 1
cv2.circle(img, (x + w, y), 3, (50, 100, 0), -1) # top Right
cv2.circle(img, (x + w, y + h), 3, (0, 0, 255), -1) # bottom Right
cv2.circle(img, (x, y), 3, (0, 255, 100), -1) # top left
cv2.circle(img, (x, y + h), 3, (255, 0, 255), -1) # bottom left
return img, points_list
if __name__ == "__main__":
net, output_layers, colors, classes = load_yolo_model()
img, height, width = load_img(IMAGES_PATH)
outs = create_blob(img, net, output_layers)
boxes, class_ids, confidences, centroids = detect_obj(outs, height, width, img)
img, points_list = draw_bounding_box(img, FONT, boxes, confidences, colors)
p1 = points_list[0][2] # window0 to window1
p2 = points_list[1][1]
p2_1 = points_list[1][2] # window1 to window2
p2_2 = points_list[2][1]
p3_1 = points_list[3][2] # window3 to window5
p5_2 = points_list[5][1]
cv2.rectangle(img, p1, p2, (255, 0, 255), -1)
cv2.rectangle(img, p2_1, p2_2, (255, 0, 255), -1)
cv2.rectangle(img, p3_1, p5_2, (255, 0, 255), -1)
cv2.imshow('out', img)
cv2.waitKey(0)
Also if you see the photo you will see the windows detected randomly and the Id number for each window does not order. How can I solve this problem? thanks in advance for helping:)

Have you tried Image Segmentation to find the objects on wall? then with a simple trick like finding the countors you can measure the distance between the objects like windows as you said.
2nd trick:
I've got another easy way which may help you:
first of all, find the edges using canny edg detection, the with dilate function fill the middle space of vertical edges between windows then by Hough Line Detection you can find the vertical lines of windows, and get the distance between the y axis of vertical lines of the wall.

Related

How to use a variable in a function from an earlier list in nested list comprehension

import cv2
import pytesseract
pytesseract.pytesseract.tesseract_cmd="D:\\Tesseract\\tesseract.exe"
i = cv2.imread('1.png')
himg,wimg,_ = i.shape
[cv2.putText(i, b[0], (x, himg - y + 25), cv2.FONT_HERSHEY_SIMPLEX, 1, (50, 50, 255), 2) for x,y,w,h in [[int(x) for x in n ]for n in [[a[1],a[2],a[3],a[4]] for a in [b.split(' ') for b in pytesseract.image_to_boxes(i).splitlines()]]]]
cv2.imshow('',i)
cv2.waitKey(0)
in the line [cv2.putText(i, b[0], (x, himg - y + 25), cv2.FONT_HERSHEY_SIMPLEX, 1, (50, 50, 255), 2) for x,y,w,h in [[int(x) for x in n ]for n in [[a[1],a[2],a[3],a[4]] for a in [b.split(' ') for b in pytesseract.image_to_boxes(i).splitlines()]]]] , I get an error mainly because I am trying to use the the variable 'b' in my final function from an earlier list in the list comprehension.
I know this because [cv2.rectangle(i, (x,himg- y), (w,himg -h), (265,0,0), 2) for x,y,w,h in [[int(x) for x in n ]for n in [[a[1],a[2],a[3],a[4]] for a in [b.split(' ') for b in pytesseract.image_to_boxes(i).splitlines()]]]]
Works perfectly fine. Pls tell a way to achieve the desired result while maintaining the list comprehension.
I believe this alternate approach does what you seek to do:
import cv2
import pytesseract
pytesseract.pytesseract.tesseract_cmd="D:\\Tesseract\\tesseract.exe"
font = cv2.FONT_HERSHEY_SIMPLEX
fontScale = 1
color = (50, 50, 255)
thickness = 2
image = cv2.imread('1.png')
image_height, image_width = image.shape
for row in pytesseract.image_to_boxes(image).splitlines():
cells = row.split(' ')
text = cells[0]
x, y, w, h = map(int, cells[1:5])
origin = (x, image_height - y + 25)
cv2.putText(image, text, origin, font, fontScale, color, thickness)
cv2.imshow('',image)
cv2.waitKey(0)

Is there any way to calculate the white distance from the image using python opencv

As you can see in the image, the size of the image is 2000*2000. We have to find the distance of the image from all the 4 coordinates. I am trying with opencv contours but on some other image it is not working.
image = cv2.imread(image_full_path)
ori_h, ori_w, _ = image.shape
print("Original height, width-->", ori_h, ori_w)
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY) # grayscale
_, thresh = cv2.threshold(gray, 150, 255, cv2.THRESH_BINARY_INV) # threshold
kernel = cv2.getStructuringElement(cv2.MORPH_CROSS, (3, 3))
dilated = cv2.dilate(thresh, kernel, iterations=13) # dilate
contours, hierarchy = cv2.findContours(dilated, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE) # get contours
idx = 0
# for each contour found, draw a rectangle around it on original image
# print('length', len(contours))
for contour in contours:
idx += 1
# get rectangle bounding contour
[x, y, w, h] = cv2.boundingRect(contour)
remaining_height_bottom = ori_h - (y + h)
remaining_width_right_side = ori_w - (x + w)
print("Upper Height, Right Width-->", y, x)
print("Bottom Height, Left Width-->", remaining_height_bottom, remaining_width_right_side)
print("Image Height, Image Width-->", h, w)
Thanks in advance.If anyone thinks that the way of asking questions is wrong please ignore. I really need help.
Please find the code below it working for me
img = cv2.imread(file_full_path) # Read in the image and convert to grayscale
ori_h, ori_w, _ = img.shape
scrollbarright = 20
img = img[:, :-scrollbarright]
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
gray = 255*(gray < 128).astype(np.uint8)
coords = cv2.findNonZero(gray)
x, y, w, h = cv2.boundingRect(coords)
print("I am ",x,y,w,h)
remaining_height_bottom = ori_h - (y + h)
remaining_width_right_side = ori_w - (x + w)
print("Upper Height, Right Width-->", y, x)
print("Bottom Height, Left Width-->", remaining_height_bottom, remaining_width_right_side)
print("Image Height, Image Width-->", h, w)
print("Original Image Height,Original Image Width-->", ori_h, ori_w)

Delay in drawing an element with mouse click if user input is requested in open cv python

I wanted to draw points with labels at mouse click on an image. In the following code it draws blue points for first 3 left mouse clicks, thereafter red points. It works fine so far. However, if I enable the user input requesting part marked by <--- it doesn't show the 3rd blue point until I give the user input. What I was expecting was the user input request comes after it draws the 3rd blue point. Any help is appreciated. Thanks !!
Here's the code. Please comment out <--- marked line #26 which calls for the user input and it works fine.
import cv2
img_path = r'test.jpg'
count = 0
red_count = 0
user_inp = None
def click_event(event, x, y, flags, params):
global count, red_count, user_inp
font_scale, point_radius = 0.4, 2
font = cv2.FONT_HERSHEY_SIMPLEX
if event == cv2.EVENT_LBUTTONDOWN:
if count < 3:
text = f"blue{count}"
cv2.putText(img, text, (x + 2, y), font, font_scale, (255, 0, 0), 1)
cv2.circle(img, (x, y), radius=point_radius, color=(255, 0, 0), thickness=-1)
cv2.imshow('image', img)
if count == 2:
print("blue index 2")
user_inp = input('input anything: ') # <------------ check here
if count >= 3:
text = f"red{red_count}"
cv2.putText(img, text, (x + 2, y), font, font_scale, (0, 0, 255), 1)
cv2.circle(img, (x, y), radius=point_radius, color=(0, 0, 255), thickness=-1)
cv2.imshow('image', img)
red_count += 1
count += 1
if __name__ == "__main__":
img = cv2.imread(img_path, 1)
cv2.imshow('image', img)
cv2.setMouseCallback('image', click_event)
cv2.waitKey(0)
cv2.destroyAllWindows()
print(user_inp)

How to check if a point is in an ellipse in python

How do I find a point within an angled ellipse in python? I wrote out the equation in a function and I am drawing a black picture with the ellipse in white and the point in blue. I am then calculating if the point is within the ellipse which it is showing up in the picture but the function is returning as false. What am I missing?
Thanks!
# Create a black image for ellipse ROI
img = np.zeros((240, 320, 3), np.uint8)
# ellipse
ellipse_center_x = 160
ellipse_center_y = 120
ellipse_axis_x = 100
ellipse_axis_y = 20
ellipse_angle = -40
start_angle = 0
end_angle = 360
# detection point example
xCenter = 135
yCenter = 135
def pointInEllipse(img, xp, yp, x, y, axis_x, axis_y, angle):
# # WITH StackOverflow Answer Edits
angle_rad = math.radians(angle)
cosa = math.cos(angle_rad)
sina = math.sin(angle_rad)
# # Equation of point within angled ellipse
a = (((cosa * (xp - x) + sina * (yp - y)) ** 2) / (axis_x**2))
b = (((sina * (xp - x) - cosa * (yp - y)) ** 2) / (axis_y**2))
result = a+b
img = cv2.ellipse(img, (x, y), (axis_x, axis_y), angle, 0, 360, (255, 255, 255), 1)
if result <= 1:
img = cv2.circle(img, (xp, yp), 10, (255, 0, 0), -1)
print(result)
cv2.imwrite('/tmp/ellipse2.png', img)
return True
else:
img = cv2.circle(img, (xp, yp), 10, (255, 0, 0), -1)
print(result)
cv2.imwrite('/tmp/ellipse2.png', img)
return False
print(pointInEllipse(img, xCenter, yCenter, ellipse_center_x, ellipse_center_y, ellipse_axis_x, ellipse_axis_y,ellipse_angle))
The cosa and sina values are wrong: math.sin and math.cos expect their arguments in radians (0 to 2π for a full circle), but you are passing an angle in degrees.
To convert an angle from degrees to radians, use the math.radians function:
angle_rad = math.radians(angle)
cosa = math.cos(angle_rad)
sina = math.sin(angle_rad)

How to recognize and count circles in a rectangle?

I would like to count how many circles are in static rectangles for more than 3 seconds. The circles represent the center of objects recognized by the camera and static rectangles are areas of interest where I would like to count the total amount of circles that are inside the area of interest for more than 3 seconds. Currently I am able to recognize objects in real-time, find the center of each object and draw static rectangles, but I don't know how to do the rest. Below is my current while loop. Any help would be greatly appreciated.
while True:
frame = vs.read()
frame = imutils.resize(frame, width=720)
box_one = cv2.rectangle(frame, (30,30), (330,330), color, 2)
box_two = cv2.rectangle(frame, (350,30), (630,330), color, 2)
(h, w) = frame.shape[:2]
blob = cv2.dnn.blobFromImage(cv2.resize(frame, (300, 300)),
0.007843, (300, 300), 127.5)
net.setInput(blob)
detections = net.forward()
for i in np.arange(0, detections.shape[2]):
confidence = detections[0, 0, i, 2]
if confidence > args["confidence"]:
idx = int(detections[0, 0, i, 1])
box = detections[0, 0, i, 3:7] * np.array([w, h, w, h])
(startX, startY, endX, endY) = box.astype("int")
label = "{}: {:.2f}%".format(CLASSES[idx],
confidence * 100)
cv2.rectangle(frame, (startX, startY), (endX, endY),
COLORS[idx], 2)
center = ((startX+endX)/2, (startY+endY)/2)
first_value = int(center[0])
second_value = int(center[1])
coordinates = (first_value, second_value)
cv2.circle(frame, coordinates, 5, (255,255,255), -1)
cv2.imshow("Frame", frame)
key = cv2.waitKey(1) & 0xFF
The output looks like this

Resources