I'm seeking assistance with writing a code snippet to achieve a specific task. I would like to apply a grid to an image and draw a perpendicular line for the highest point within each of the outermost grids. If anyone is familiar with how to accomplish this, I would greatly appreciate your guidance. Thank you in advance for your help!
import cv2
import numpy as np
# Load the image
image = cv2.imread('01_img_original.JPG')
# Define grid parameters
grid_size = 50 # Size of each grid cell
grid_thickness = 1 # Thickness of the grid lines
# Calculate the number of rows and columns in the grid
rows, cols, \_ = image.shape
num_rows = rows // grid_size
num_cols = cols // grid_size
# Draw the grid lines
for i in range(num_rows + 1):
y = i \* grid_size
cv2.line(image, (0, y), (cols, y), (0, 255, 0), grid_thickness)
for j in range(num_cols + 1):
x = j \* grid_size
cv2.line(image, (x, 0), (x, rows), (0, 255, 0), grid_thickness)
# Find the maximum intensity point in the outermost grids
max_intensity = 0
max_point = None
for i in range(num_rows + 1):
for j in range(num_cols + 1):
if i == 0 or i == num_rows or j == 0 or j == num_cols:
\# Get the grid boundaries
y1 = i \* grid_size
y2 = min((i + 1) \* grid_size, rows)
x1 = j \* grid_size
x2 = min((j + 1) \* grid_size, cols)
# Find the maximum intensity point within the grid
grid = image[y1:y2, x1:x2]
grid_gray = cv2.cvtColor(grid, cv2.COLOR_BGR2GRAY)
min_val, max_val, min_loc, max_loc = cv2.minMaxLoc(grid_gray)
# Check if the maximum intensity point is greater than previous max
if max_val > max_intensity:
max_intensity = max_val
max_point = (max_loc[0] + x1, max_loc[1] + y1)
# Draw a line from the maximum point to the image border
cv2.line(image, max_point, (max_point\[0\], 0), (0, 0, 255), 2)
cv2.line(image, max_point, (0, max_point\[1\]), (0, 0, 255), 2)
# Display the image with grid and lines
cv2.imshow('Grid with Maximum Point Distance', image)
cv2.waitKey(0)
cv2.destroyAllWindows()
This implements most of what I was talking about. Here's the philosophy. This code is quite different from my first answer, and uses a different philosophy, focusing on the lines rather than the grid cells.
For each row, find the left and right edge of the blob. For each column, find the top and right edge of the blob. Now, subdivide the image into the larger grid. Scan across until we find the first cell that has a piece of the blob. Now we start collecting points for a polyline. For each cell, we draw a line up to the level line for the cell, then we add a point for the other side of the cell. This way, we can remember the Y coordinate of the last cell, so we can draw your connecting lines.
We repeat that for the left edge, the bottom edge, and the right edge. Then, we have four sets of lines (a "polyline") that we can pass to OpenCV. There is some mucking around with the points to make the corners square where there are intersections, but it's not too bad.
I've learned that this algorithm is not bulletproof. It works for this image, but if you have a blob with concave sections or ledges, this would not work, and I'm not sure of a general-purpose algorithm that would.
import cv2
import sys
import numpy as np
image = cv2.imread('blob.jpg')
#mono = image[:,:,0]
mono = cv2.cvtColor(image,cv2.COLOR_BGR2GRAY)
rows, cols = mono.shape
# For each row and column, find the spot where the blob begins or ends.
left = np.ones(rows,dtype=int) * cols
right = np.zeros(rows,dtype=int)
for row in range(rows):
idx = np.where(mono[row,:] < 240)[0]
if idx.size:
left[row] = idx[0]
right[row] = idx[-1]
top = np.ones(cols,dtype=int) * rows
bot = np.zeros(cols,dtype=int)
for col in range(cols):
idx = np.where(mono[:,col] < 240)[0]
if idx.size:
top[col] = idx[0]
bot[col] = idx[-1]
grid_size = 50
gw = cols//grid_size
gh = rows//grid_size
def togrid(n):
return n*grid_size, (n+1)*grid_size
# For each larger grid column, mark where the top and bottom are.
gtop = np.zeros(gw,dtype=int)
gbot = np.zeros(gw,dtype=int)
gleft = np.zeros(gh,dtype=int)
gright = np.zeros(gh,dtype=int)
for xn in range(gw):
x0, x1 = togrid(xn)
gtop[xn] = np.min( top[x0:x1] )
gbot[xn] = np.max( bot[x0:x1] )
# For each larger grid row, mark where the left and right are.
for yn in range(gh):
y0, y1 = togrid(yn)
gleft[yn] = np.min( left[y0:y1] )
gright[yn] = np.max( right[y0:y1] )
# Build coordinates of the top line.
top = []
y99 = 0
for xn,y in enumerate(gtop):
x0, x1 = togrid(xn)
if y < rows:
# Step from the last, unless there is no last.
if not y99:
if y > rows // 2:
continue
x = gleft[y//grid_size]
top.append( (x, y) )
elif y != y99:
top.append( (x0, y99) )
top.append( (x0, y) )
top.append( (x1, y) )
y99 = y
top[-1] = (gright[y99//grid_size], top[-1][1])
left = []
x99 = 0
y99 = top[0][1]
for yn,x in enumerate(gleft):
y0, y1 = togrid(yn)
if x < cols and y1 > y99:
# Step from the last, unless there is no last.
if not x99:
left.append( (x, y99) )
elif x - x99 > grid_size:
break
elif x != x99:
left.append( (x99, y0) )
left.append( (x, y0) )
left.append( (x, y1) )
x99 = x
left[-1] = (left[-1][0], gbot[x99//grid_size])
bot = []
x99 = left[-1][0]
y99 = 0
for xn,y in enumerate(gbot):
x0, x1 = togrid(xn)
if y and x1 > x99:
# Step from the last, unless there is no last.
if not y99:
if y < rows // 2:
continue
x = gleft[y//grid_size]
bot.append( (x, y) )
elif y != y99:
bot.append( (x0, y99) )
bot.append( (x0, y) )
bot.append( (x1, y) )
y99 = y
bot[-1] = (gright[y99//grid_size], bot[-1][1])
right = []
x99 = 0
y99 = top[-1][1]
for yn,x in enumerate(gright):
y0, y1 = togrid(yn)
if x and y1 > y99:
# Step from the last, unless there is no last.
if not x99:
right.append( (x, y99) )
elif x != x99:
right.append( (x99, y0) )
right.append( (x, y0) )
right.append( (x, y1) )
x99 = x
right[-1] = (right[-1][0], gbot[x99//grid_size])
# Draw the grid lines.
for yn in range(gh):
y0, y1 = togrid(yn)
cv2.line(image, (0, y0), (cols, y0), (255, 0, 0), 1)
for xn in range(gw):
x0, x1 = togrid(xn)
cv2.line(image, (x0, 0), (x0, rows), (128, 0, 0), 1)
# Draw edge lines.
def drawline(points,clr):
color = (255 if clr&4 else 0, 255 if clr&2 else 0, 255 if clr&1 else 0)
x0,y0 = (-1,-1)
for x,y in points:
if x0 > 0:
cv2.line( image, (x0,y0), (x,y), color, 3)
x0,y0 = x,y
drawline(left,4)
drawline(top,2)
drawline(right,1)
drawline(bot,6)
cv2.imshow("see this", image)
cv2.waitKey(0)