Drawing Scaled grid system using openCV and python - python-3.x

What I want to do is draw a grid on an image that has smaller squares at the top and larger ones near the bottom. I am lost on how to do this though. I figured out how to draw a grid on the image using open cv but don't know how to fine turn it to get the results I want.
What I will be using this for is to find where a bounding box point is for a detected object. I will need a smaller bounding box at the top and a larger one closer to the bottom of the image.
This is what I want to do:
But I cannot figure out how to get the curves in the code.
This is what I have so far:
And this the is code that I am using.
'''
#This method draws simple grid overthe image based on the passed step
#The pxstep controls the size of the grid
'''
def drawBasicGrid(image, pxstep, midX, midY):
x = pxstep
y = pxstep
#Draw all x lines
while x < img.shape[1]:
cv2.line(img, (x, 0), (x, img.shape[0]), color=(255, 0, 255), thickness=1)
x += pxstep
while y < img.shape[0]:
cv2.line(img, (0, y), (img.shape[1], y), color=(255, 0, 255),thickness=1)
y += pxstep
This draws the basic grid.
and this creates thebounding boxes that I use for detection of the bounding points of a detected object.
def makeBoundingBox(h,w, step):
#BBox is 100*100 square or step which is defied
y = 0
bbox = []
while y < h:
#print("Y value", y)
x=0
while x < w:
#print("X Value", x)
bbox.append([(x,y), (x+step, y+step)])
x += step
y += step
return bbox
And this is how I am using it.
#Prepare Images
img = cv2.imread(image)
#img = imutils.resize(img, width=300)
#gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
(H,W) = img.shape[:2]
#Create bounding boxes for the image
'''
#Creates the boxes for people detection
#It will look for which bounding boxes the person is in and then
#Draw a box around their feet
'''
#People Detection
blob = cv2.dnn.blobFromImage(cv2.resize(img, (300, 300)),0.007843,(300, 300), 127.5)
net.setInput(blob)
detections = net.forward()
'''
#Get the center point of the image
'''
midY = H//2
midX = W//2
print("Middle Y pixel", midY)
#Draw center line
cv2.line(img, (0, midY), (W, midY), color=green, thickness=2)
cv2.line(img, (midX, 0), (midX, H), color=green, thickness=2)
#Visual grid drawn
drawBasicGrid(img, step, midX,midY)
bbox = makeBoundingBox(H, W, step) #Used for finding where the endx and startx BBOX points are
Any help on this will be appreciated.

Related

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)

How to count the vehicles if boundingRect touch the line

Below is the code i am trying:
def mouse_drawing(event, x, y, flags, params):
global point1, point2, drawing
if event == cv2.EVENT_LBUTTONDOWN:
if drawing is False:
drawing = True
point1 = (x, y)
else:
drawing = False
elif event == cv2.EVENT_MOUSEMOVE:
if drawing is True:
point2 = (x, y)
cap = cv2.VideoCapture("new2.asf")
cv2.namedWindow("App", cv2.WINDOW_FREERATIO)
cv2.setMouseCallback("App", mouse_drawing)
fgbg = cv2.createBackgroundSubtractorMOG2()
kernel = np.ones((5, 5), np.uint8)
while True:
ret, frame = cap.read()
frame = cv2.resize(frame,None,fx=scaling_factorx,fy=scaling_factory,interpolation=cv2.INTER_AREA)
imgray = cv2.cvtColor(frame,cv2.COLOR_BGR2GRAY)
fgmask1 = cv2.GaussianBlur(imgray, (7,7), 0)
fgmask = fgbg.apply(fgmask1)
if point1 and point2:
cv2.line(frame, point1, point2, (0, 255, 0), 3)
contours, hierarchy = cv2.findContours(fgmask, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
try:
hierarchy = hierarchy[0]
except:
hierarchy = []
for contour, hier in zip(contours, hierarchy):
(x, y, w, h) = cv2.boundingRect(contour)
if w > 80 and h > 80:
cv2.rectangle(frame, (x,y), (x+w,y+h), (0, 255, 0), 2)
cv2.imshow("App", frame)
How to write a image of a vehicle with cv2.imwrite which is reached the line, the line which is drawn as manually. And the vehicles are having the rectangular boxes that's fine But some vehicles having more than one box. One vehicle should be have only one rectangular box. And that should be saved if reached the line, rest of vehicles should not to be saved. Please let me know the solution.
First, you need to group intersecting rectangles into one.
You do so by checking the intersection area between each pair of rectangles.
If the intersection area is larger than a pre-defined heuristic ratio of the small rectangle area then the smaller rectangle should be removed. For example, intersection_area / smaller_rect_area > 0.75
Please check this answer for the rectangles intersection.
Second, to check that a rectangle has passed the line:
Use your points to find the parameters for the general line formula: ax + by + c = 0
For each frame, plug the rectangle center coordinates in the formula and keep track of the sign of the result.
If the sign of the result changes that means that the rectangle center has passed the line.

Crop Binary Image on Object Height and Width

I have this image:
character
I have successfully isolated the character, and now I want to crop the image to bounds of the binary object. Here is the cleaned up image that I want to crop: edited
I can't seem to figure out the code. Here is what I've tried:
inv = cv2.bitwise_not(img)
mask = np.zeros(img.shape, np.uint8)
_, cnts, hier = cv2.findContours(img.copy(), cv2.RETR_LIST, cv2.CHAIN_APPROX_SIMPLE)
for c in cnts:
if cv2.contourArea(c) > 100:
cv2.drawContours(mask, [c], 0, 255, -1)
x, y, h, w = cv2.boundingRect(c)
roi = mask[y:y + h, x:x + w]
crop = img[y:y + h, x:x + w]
final = crop * (roi / 255)
You can simply use max to find the largest contour and cv2.boundingRect to find the coordinates of the largest contour after which you can crop it.
c = max(contours, key = cv2.contourArea)
x,y,w,h = cv2.boundingRect(c)
It would be better to use cv2.RETR_EXTERNAL instead of cv2.RETR_LIST while using cv2.findContours as in this case as it you are looking for only the boundry of the object and not internal details.
if you want to crop an image with the points (x1,y1) and (x2,y2)
(x1,y1)+-------+
| |
| |
+-------+(x2,y2)
## mask is a numpy array (an image)
croped_image = mask[y1:y2, x1:x2] ## this will return a cropped image
but for your question you want the bounding rectangle to crop the binary image i guess
see : https://docs.opencv.org/3.1.0/dd/d49/tutorial_py_contour_features.html
_, contours, _ = cv2.findContours( mask, cv2.RETR_TREE, cv2.CHAIN_APPROX_NONE )
contour = max(contours, key = cv2.contourArea)
x, y, w, h = cv2.boundingRect(contour)
x1, y1, x2, y2 = x, y, x+w, y+h
now use these points to crop the image

Resizing image and its bounding box

I have an image with bounding box in it, and I want to resize the image.
img = cv2.imread("img.jpg",3)
x_ = img.shape[0]
y_ = img.shape[1]
img = cv2.resize(img,(416,416));
Now I want to calculate the scale factor:
x_scale = ( 416 / x_)
y_scale = ( 416 / y_ )
And draw an image, this is the code for the original bounding box:
( 128, 25, 447, 375 ) = ( xmin,ymin,xmax,ymax)
x = int(np.round(128*x_scale))
y = int(np.round(25*y_scale))
xmax= int(np.round (447*(x_scale)))
ymax= int(np.round(375*y_scale))
However using this I get:
While the original is:
I don't see any flag in this logic, what's wrong?
Whole code:
imageToPredict = cv2.imread("img.jpg",3)
print(imageToPredict.shape)
x_ = imageToPredict.shape[0]
y_ = imageToPredict.shape[1]
x_scale = 416/x_
y_scale = 416/y_
print(x_scale,y_scale)
img = cv2.resize(imageToPredict,(416,416));
img = np.array(img);
x = int(np.round(128*x_scale))
y = int(np.round(25*y_scale))
xmax= int(np.round (447*(x_scale)))
ymax= int(np.round(375*y_scale))
Box.drawBox([[1,0, x,y,xmax,ymax]],img)
and drawbox
def drawBox(boxes, image):
for i in range (0, len(boxes)):
cv2.rectangle(image,(boxes[i][2],boxes[i][3]),(boxes[i][4],boxes[i][5]),(0,0,120),3)
cv2.imshow("img",image)
cv2.waitKey(0)
cv2.destroyAllWindows()
The image and the data for the bounding box are loaded separately. I am drawing the bounding box inside the image. The image does not contain the box itself.
I believe there are two issues:
You should swap x_ and y_ because shape[0] is actually y-dimension and shape[1] is the x-dimension
You should use the same coordinates on the original and scaled image. On your original image the rectangle is (160, 35) - (555, 470) rather than (128,25) - (447,375) that you use in the code.
If I use the following code:
import cv2
import numpy as np
def drawBox(boxes, image):
for i in range(0, len(boxes)):
# changed color and width to make it visible
cv2.rectangle(image, (boxes[i][2], boxes[i][3]), (boxes[i][4], boxes[i][5]), (255, 0, 0), 1)
cv2.imshow("img", image)
cv2.waitKey(0)
cv2.destroyAllWindows()
def cvTest():
# imageToPredict = cv2.imread("img.jpg", 3)
imageToPredict = cv2.imread("49466033\\img.png ", 3)
print(imageToPredict.shape)
# Note: flipped comparing to your original code!
# x_ = imageToPredict.shape[0]
# y_ = imageToPredict.shape[1]
y_ = imageToPredict.shape[0]
x_ = imageToPredict.shape[1]
targetSize = 416
x_scale = targetSize / x_
y_scale = targetSize / y_
print(x_scale, y_scale)
img = cv2.resize(imageToPredict, (targetSize, targetSize));
print(img.shape)
img = np.array(img);
# original frame as named values
(origLeft, origTop, origRight, origBottom) = (160, 35, 555, 470)
x = int(np.round(origLeft * x_scale))
y = int(np.round(origTop * y_scale))
xmax = int(np.round(origRight * x_scale))
ymax = int(np.round(origBottom * y_scale))
# Box.drawBox([[1, 0, x, y, xmax, ymax]], img)
drawBox([[1, 0, x, y, xmax, ymax]], img)
cvTest()
and use your "original" image as "49466033\img.png",
I get the following image
And as you can see my thinner blue line lies exactly inside your original red line and it stays there whatever targetSize you chose (so the scaling actually works correctly).
Another way of doing this is to use CHITRA
image = Chitra(img_path, box, label)
# Chitra can rescale your bounding box automatically based on the new image size.
image.resize_image_with_bbox((224, 224))
print('rescaled bbox:', image.bounding_boxes)
plt.imshow(image.draw_boxes())
https://chitra.readthedocs.io/en/latest/
pip install chitra
I encountered an issue with bounding box coordinates in Angular when using TensorFlow.js and MobileNet-v2 for prediction. The coordinates were based on the resolution of the video frame.
but I was displaying the video on a canvas with a fixed height and width. I resolved the issue by dividing the coordinates by the ratio of the original video resolution to the resolution of the canvas.
const x = prediction.bbox[0] / (this.Owidth / 300);
const y = prediction.bbox[1] / (this.Oheight / 300);
const width = prediction.bbox[2] / (this.Owidth / 300);
const height = prediction.bbox[3] / (this.Oheight / 300);
// Draw the bounding box.
ctx.strokeStyle = '#99ff00';
ctx.lineWidth = 2;
ctx.strokeRect(x, y, width, height);
this.Owidth & this.Oheight are original resolution of video. it is obtained by.
this.video.addEventListener(
'loadedmetadata',
(e: any) => {
this.Owidth = this.video.videoWidth;
this.Oheight = this.video.videoHeight;
console.log(this.Owidth, this.Oheight, ' pixels ');
},
false
);
300 X 300 is my static canvas width and height.
you can use the resize_dataset_pascalvoc
it's easy to use python3 main.py -p <IMAGES_&_XML_PATH> --output <IMAGES_&_XML> --new_x <NEW_X_SIZE> --new_y <NEW_X_SIZE> --save_box_images <FLAG>"
It resize all your dataset and rewrite new annotations files to resized images

how to measure distance between center of objects - openCV?

I have the following code that extracts and "tracks" black objects within a video file or webcam stream. I am new to Python and CV and am struggling to understand how to extract the center points of the tracked objects for comparison.
Code:
#for this demo the only colour we are interested in is black or near black
#remember open cv uses BGR not RGB
groupColorLower = np.array([0,0,0], dtype = "uint8")
groupColorUpper = np.array([179,179,179], dtype ="uint8")
# construct the argument parse and parse the arguments
ap = argparse.ArgumentParser()
ap.add_argument("-v", "--video", required=True,
help="path to the input video file")
args = vars(ap.parse_args())
######### Reading input video or opening webcam#########
# if a video path was not supplied, grab the reference
# to the webcam
if not args.get("video", False):
camera = cv2.VideoCapture(0)
# otherwise, load the video
else:
camera = cv2.VideoCapture(args["video"])
######### Finished Reading input video or opening webcam#########
# keep looping
while True:
# grab the current frame
(grabbed, frame) = camera.read()
# if we are viewing a video and we did not grab a
# frame, then we have reached the end of the video
if args.get("video") and not grabbed:
break
# determine which pixels fall within the black boundaries
# and then blur the binary image
blue = cv2.inRange(frame, groupColorLower, groupColorUpper)
blue = cv2.GaussianBlur(blue, (3, 3), 0)
# find contours in the image
(_, contours1, _) = cv2.findContours(blue.copy(), cv2.RETR_EXTERNAL,
cv2.CHAIN_APPROX_SIMPLE)
#lets try to sort contours1 left to right
(contours1, _) = contours.sort_contours(contours1)
if len(contours1) > 0:
#now lets extract the center point of the left most contour
fixedPoint = cv2.moments(contours1[0])
fixedPointX = int (fixedPoint["m10"] / fixedPoint["m00"])
fixedPointY = int (fixedPoint["m01"] / fixedPoint["m00"])
#lets draw a white dot in left most object
cv2.circle(frame, (fixedPointX, fixedPointY), 7, (255,255,255), -1)
#lets use the nearest to fixedPoint as anchor (left most [1] where [0] is fixedPoint
if len(contours1) > 1:
# sort the contours so we can iterate over them
cnt2 = sorted([(c, cv2.boundingRect(c)[0]) for c in contours1], key = lambda x: x[1], reverse = True)
#draw boxes around all objects we are tracking
for (c, _) in cnt2:
(x, y, w, h) = cv2.boundingRect(c)
cv2.rectangle(frame, (x, y), (x + w, y +h), (255, 255, 0), 4)
M = cv2.moments(c)
cX = int(M["m10"] / M["m00"])
cY = int(M["m01"] / M["m00"])
# draw a dot in center of the black object on the image
cv2.circle(frame, (cX, cY), 7, (100, 100, 100), -1)
centre.append((int(M["m10"]/M["m00"]), int(M["m01"]/M["m00"])))
What I would like to be able to do is print the distance (in pixels) between the objects as they are found but I am not sure how to access this data.
The fixed point calculation works as I assume the left most object can be hard coded, but I need to get the coords for any other objects located.
The code currently loops over each black object and places a dot in the center of it.
Thanks for any help offered:
andy

Resources