Detect Crop Lines using opencv - python

I am working on a lane detection project and I want to feed in the path robot can take between crop rows. I initially converted the image to birds eye view for better processing and tried Hough transform, but Hough transform is not giving me good results.
Bird's eye view of the image
Are there any other approaches I am missing out?

Before applying the Hough lines algorithm you could do the following :
1)Color shifting
Apply color shifting where you split the colors of the image into blue, green and red channels. Since the crop rows are green you can amplify the color green to stand out more from the rest of the channels
b,g,r = cv2.split(img)
gscale = 2*g-r-b
2)Canny Edge Detection
Fiddle with the min and max arguments in the cv2.Canny() function until satisfactory.
gscale = cv2.Canny(gscale,minVal,maxValue)
3)Skeletonization
Skeletonization is the process of thinning the regions of interest to their binary constituents. This makes it easier for to perform pattern recognition.
size = np.size(gscale) #returns the product of the array dimensions
skel = np.zeros(gscale.shape,np.uint8) #array of zeros
ret,gscale = cv2.threshold(gscale,128,255,0) #thresholding the image
element = cv2.getStructuringElement(cv2.MORPH_CROSS,(3,3))
done = False
while( not done):
eroded = cv2.erode(gscale,element)
temp = cv2.dilate(eroded,element)
temp = cv2.subtract(gscale,temp)
skel = cv2.bitwise_or(skel,temp)
gscale = eroded.copy()
zeros = size - cv2.countNonZero(gscale)
if zeros==size:
done = True
You should get better performance in the Hough lines algorithm after applying all these in their respective order.

Related

How can I remove these parallel lines noise on my image using opencv

I'm new to opencv and I m trying to remove all these diagonal parallel lines that are noise in my image.
I have tried using HoughLinesP after some erosion/dilatation but the result is poo (and keeping only the one with a near 135 degree angle).
img = cv2.imread('images/dungeon.jpg')
ret,img = cv2.threshold(img,180,255,0)
element = cv2.getStructuringElement(cv2.MORPH_CROSS,(5,5))
eroded = cv2.erode(img,element)
dilate = cv2.dilate(eroded, element)
skeleton = cv2.subtract(img, dilate)
gray = cv2.cvtColor(skeleton,cv2.COLOR_BGR2GRAY)
minLineLength = 10
lines = cv2.HoughLinesP(gray, 1, np.pi/180, 1, 10, 0.5)
for line in lines:
for x1,y1,x2,y2 in line:
angle = math.atan2(y2-y1,x2-x1)
if (angle > -0.1 and angle < 0.1):
cv2.line(img,(x1,y1),(x2,y2),(0,255,0),1)
cv2.imshow("result", img)
cv2.waitKey(0)
cv2.destroyAllWindows()
My thinking here was to detect these lines in order to remove them afterwards but I m not even sure that's the good way to do this.
I guess you are trying to get the contours of the walls, right? Here’s a possible path to the solution using mainly spatial filtering. You will still need to clean the results to get where you want. The idea is to try and compute a mask of the parallel lines (high-frequency noise) of the image and calculate the difference between the (binary) input and this mask. These are the steps:
Convert the input image to grayscale
Apply Gaussian Blur to get rid of the high-frequency noise you are trying to eliminate
Get a binary image of the blurred image
Apply area filters to get rid of everything that is not noise, to get a noise mask
Compute the difference between the original binary mask and the noise mask
Clean up the difference image
Compute contours on this image
Let’s see the code:
import cv2
import numpy as np
# Set image path
path = "C://opencvImages//"
fileName = "map.png"
# Read Input image
inputImage = cv2.imread(path+fileName)
# Convert BGR to grayscale:
grayscaleImage = cv2.cvtColor(inputImage, cv2.COLOR_BGR2GRAY)
# Apply Gaussian Blur:
blurredImage = cv2.GaussianBlur(grayscaleImage, (3, 3), cv2.BORDER_DEFAULT)
# Threshold via Otsu:
_, binaryImage = cv2.threshold(blurredImage, 0, 255, cv2.THRESH_BINARY+cv2.THRESH_OTSU)
# Save a copy of the binary mask
binaryCopy = cv2.cvtColor(binaryImage, cv2.COLOR_GRAY2BGR)
This is the output:
Up until now you get this binary mask. The process so far has smoothed the noise and is creating thick black blobs where the noise is located. Again, the idea is to generate a noise mask that can be subtracted to this image.
Let’s apply an area filter and try to remove the big white blobs, which are NOT the noise we are interested to preserve. I’ll define the function towards the end, for now I just want to present the general idea:
# Set the minimum pixels for the area filter:
minArea = 50000
# Perform an area filter on the binary blobs:
filteredImage = areaFilter(minArea, binaryImage)
The filter will suppress every white blob that is above the minimum threshold. The value is big because in this particular case we are interested in preserving only the black blobs. This is the result:
We have a pretty solid mask. Let’s subtract this from the original binary mask we created earlier:
# Get the difference between the binary image and the mask:
imgDifference = binaryImage - filteredImage
This is what we get:
The difference image has some small noise. Let’s apply the area filter again to get rid of it. This time with a more traditional threshold value:
# Set the minimum pixels for the area filter:
minArea = 20
# Perform an area filter on the binary blobs:
filteredImage = areaFilter(minArea, imgDifference)
Cool. This is the final mask:
Just for completeness. Let’s compute contours on this input, which is very straightforward:
# Find the big contours/blobs on the filtered image:
contours, hierarchy = cv2.findContours(filteredImage, cv2.RETR_CCOMP, cv2.CHAIN_APPROX_SIMPLE)
# Draw the contours on the mask image:
cv2.drawContours(binaryCopy, contours, -1, (0, 255, 0), 3)
Let’s see the result:
As you see it is not perfect. However, there’s still some room for improvement, perhaps you can polish a little bit more this idea to get a potential solution. Here's the definition and implementation of the areaFilter function:
def areaFilter(minArea, inputImage):
# Perform an area filter on the binary blobs:
componentsNumber, labeledImage, componentStats, componentCentroids = \
cv2.connectedComponentsWithStats(inputImage, connectivity=4)
# Get the indices/labels of the remaining components based on the area stat
# (skip the background component at index 0)
remainingComponentLabels = [i for i in range(1, componentsNumber) if componentStats[i][4] >= minArea]
# Filter the labeled pixels based on the remaining labels,
# assign pixel intensity to 255 (uint8) for the remaining pixels
filteredImage = np.where(np.isin(labeledImage, remainingComponentLabels) == True, 255, 0).astype('uint8')
return filteredImage

General Object Counting Python OpenCV

I'm trying to make a general object counting algorithm using python and openCV (open to try other methods) however I can't seem to get a good count on a variety of objects and don't know how to accomodate for that
https://imgur.com/a/yAkRxWH are some example test images.
This is for to speed up inventory counting of smaller objects.
**EDIT
This is my current code (simple blob detector)
# Standard imports
import cv2
import numpy as np;
# Read image
im = cv2.imread("./images/screw_simple.jpg", cv2.IMREAD_GRAYSCALE)
im = cv2.resize(im, (1440, 880))
# Setup SimpleBlobDetector parameters.
params = cv2.SimpleBlobDetector_Params()
# Change thresholds
params.minThreshold = 10 #10
params.maxThreshold = 200 #200
# Filter by Area.
params.filterByArea = True # True
params.minArea = 500 #1500
# Filter by Circularity
params.filterByCircularity = True #True
params.minCircularity = 0.1 #0.1
# Filter by Convexity
params.filterByConvexity = True #True
params.minConvexity = 0.0 #0.87
# Filter by Inertia
params.filterByInertia = True #True
params.minInertiaRatio = 0.0 #0.01
# Create a detector with the parameters
ver = (cv2.__version__).split('.')
if int(ver[0]) < 3:
detector = cv2.SimpleBlobDetector(params)
else:
detector = cv2.SimpleBlobDetector_create(params)
# Detect blobs.
keypoints = detector.detect(im)
# Draw detected blobs as red circles.
# cv2.DRAW_MATCHES_FLAGS_DRAW_RICH_KEYPOINTS ensures
# the size of the circle corresponds to the size of blob
total_count = 0
for i in keypoints:
total_count = total_count + 1
im_with_keypoints = cv2.drawKeypoints(im, keypoints, np.array([]), (0, 0, 255), cv2.DRAW_MATCHES_FLAGS_DRAW_RICH_KEYPOINTS)
# Show blobs
cv2.imshow("Keypoints", im_with_keypoints)
cv2.waitKey(0)
print(total_count)
Here are the results I'm getting: https://imgur.com/a/id6OlIA
How can I improve this algorithm to get better detection for a general use case of objects without having to modify the parameters each time for each object?
You can try with an OpenCV approach, you could use a
SimpleBlobDetector
Obviously this is a test image and the result I got is also not perfect, since there are a lot of hyperparameters to set. The hyperparameters make it pretty flexible, so it is a decent place to start from.
This is what the Detector does (see details here):
Thresholding: Convert the source images to several binary images by thresholding the source image with thresholds starting at minThreshold. These thresholds are incremented by thresholdStep until maxThreshold. So the first threshold is minThreshold, the second is minThreshold + thresholdStep, the third is minThreshold + 2 x thresholdStep, and so on.
Grouping: In each binary image, connected white pixels are grouped together. Let’s call these binary blobs.
Merging: The centers of the binary blobs in the binary images are computed, and blobs located closer than minDistBetweenBlobs are merged.
Center & Radius Calculation: The centers and radii of the new merged blobs are computed and returned.
Find the code bellow the image.
# Standard imports
import cv2
import numpy as np
# Read image
im = cv2.imread("petri.png", cv2.IMREAD_COLOR)
# Setup SimpleBlobDetector parameters.
params = cv2.SimpleBlobDetector_Params()
# Change thresholds
params.minThreshold = 0
params.maxThreshold = 255
# Set edge gradient
params.thresholdStep = 5
# Filter by Area.
params.filterByArea = True
params.minArea = 10
# Set up the detector with default parameters.
detector = cv2.SimpleBlobDetector_create(params)
# Detect blobs.
keypoints = detector.detect(im)
# Draw detected blobs as red circles.
# cv2.DRAW_MATCHES_FLAGS_DRAW_RICH_KEYPOINTS ensures the size of the circle corresponds to the size of blob
im_with_keypoints = cv2.drawKeypoints(im, keypoints, np.array([]), (0, 0, 255),
cv2.DRAW_MATCHES_FLAGS_DRAW_RICH_KEYPOINTS)
# Show keypoints
cv2.imshow("Keypoints", im_with_keypoints)
cv2.waitKey(0)
For better readability I rather put this in a second answer: You could
use a segmentation approach e.g. watershed algorithm
Any grayscale image can be viewed as a topographic surface where high intensity denotes peaks and hills while low intensity denotes valleys. You start filling every isolated valleys (local minima) with different colored water (labels). As the water rises, depending on the peaks (gradients) nearby, water from different valleys, obviously with different colors will start to merge. To avoid that, you build barriers in the locations where water merges. You continue the work of filling water and building barriers until all the peaks are under water. Then the barriers you created gives you the segmentation result. This is the "philosophy" behind the watershed.

How to remove hair from skin images using opencv?

I am working with recognition of skin spots. For this, I work with a number of images with different noises. One of these noises are the hairs, because I have images with hairs over the area of ​​the stain (ROI). How to decrease or remove these types of image noise?
The code below decreases the area where hairs are, but does not remove hairs that are above the area of ​​interest (ROI).
import numpy as np
import cv2
IMD = 'IMD436'
# Read the image and perfrom an OTSU threshold
img = cv2.imread(IMD+'.bmp')
gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
ret, thresh = cv2.threshold(gray,0,255,cv2.THRESH_BINARY_INV+cv2.THRESH_OTSU)
# Remove hair with opening
kernel = np.ones((2,2),np.uint8)
opening = cv2.morphologyEx(thresh,cv2.MORPH_OPEN,kernel, iterations = 2)
# Combine surrounding noise with ROI
kernel = np.ones((6,6),np.uint8)
dilate = cv2.dilate(opening,kernel,iterations=3)
# Blur the image for smoother ROI
blur = cv2.blur(dilate,(15,15))
# Perform another OTSU threshold and search for biggest contour
ret, thresh = cv2.threshold(blur,0,255,cv2.THRESH_BINARY+cv2.THRESH_OTSU)
contours, hierarchy = cv2.findContours(thresh,cv2.RETR_TREE,cv2.CHAIN_APPROX_NONE)
cnt = max(contours, key=cv2.contourArea)
# Create a new mask for the result image
h, w = img.shape[:2]
mask = np.zeros((h, w), np.uint8)
# Draw the contour on the new mask and perform the bitwise operation
cv2.drawContours(mask, [cnt],-1, 255, -1)
res = cv2.bitwise_and(img, img, mask=mask)
# Display the result
cv2.imwrite(IMD+'.png', res)
cv2.imshow('img', res)
cv2.waitKey(0)
cv2.destroyAllWindows()
Exit:
How can I remove hair from the top of my region of interest?
Images used:
I am responding to your tag on a related post. As I understand you and another colege are working together on a project to locate the moles on the skin? Because I think I have already gave help to one or maybe both of you on similar questions and already mentioned that the removal of the hair is very tricky and difficult task. If you remove the hair on the image you lose information and you can't replace that part of the image (no program or alghorithm can guess what is under the hair - but it can make an estimation). What you could do as I mentioned in other posts and I think that it would be the best approach is to learn about deep neural networks and make your own for the hair removal. You can google "watermark removal deep neural network" and see what I mean. That being said, your code does not seem to extract all ROIs (the moles) you have given in the example image. I have made another example on how you can better extract the moles. Basically you should perform closing before transforming to binary and you will get better results.
For the second part - hair removal, if you do not wish to make a neural network, I think that alternative solution could be, that you calculate the mean pixel intesity of the region that contains the mole. Then iterate throug every pixel and make some sort of criteria on how much can the pixel differ from the mean. Hair seem to be presented with pixels that are darker than the mole area. So when you find the pixel, replace it with the neigbour pixel that does not fall in this criteria. In the example I have made a simple logic which will not work with every image but it can serve as an example. To make a fully operational solution you should make a better, more complex alghorithm which I guess will take quite some time. Hope it helps a bit! Cheers!
import numpy as np
import cv2
from PIL import Image
# Read the image and perfrom an OTSU threshold
img = cv2.imread('skin2.png')
kernel = np.ones((15,15),np.uint8)
# Perform closing to remove hair and blur the image
closing = cv2.morphologyEx(img,cv2.MORPH_CLOSE,kernel, iterations = 2)
blur = cv2.blur(closing,(15,15))
# Binarize the image
gray = cv2.cvtColor(blur,cv2.COLOR_BGR2GRAY)
_, thresh = cv2.threshold(gray,0,255,cv2.THRESH_BINARY_INV+cv2.THRESH_OTSU)
# Search for contours and select the biggest one
_, contours, hierarchy = cv2.findContours(thresh,cv2.RETR_TREE,cv2.CHAIN_APPROX_NONE)
cnt = max(contours, key=cv2.contourArea)
# Create a new mask for the result image
h, w = img.shape[:2]
mask = np.zeros((h, w), np.uint8)
# Draw the contour on the new mask and perform the bitwise operation
cv2.drawContours(mask, [cnt],-1, 255, -1)
res = cv2.bitwise_and(img, img, mask=mask)
# Calculate the mean color of the contour
mean = cv2.mean(res, mask = mask)
print(mean)
# Make some sort of criterion as the ratio hair vs. skin color varies
# thus makes it hard to unify the threshold.
# NOTE that this is only for example and it will not work with all images!!!
if mean[2] >182:
bp = mean[0]/100*35
gp = mean[1]/100*35
rp = mean[2]/100*35
elif 182 > mean[2] >160:
bp = mean[0]/100*30
gp = mean[1]/100*30
rp = mean[2]/100*30
elif 160>mean[2]>150:
bp = mean[0]/100*50
gp = mean[1]/100*50
rp = mean[2]/100*50
elif 150>mean[2]>120:
bp = mean[0]/100*60
gp = mean[1]/100*60
rp = mean[2]/100*60
else:
bp = mean[0]/100*53
gp = mean[1]/100*53
rp = mean[2]/100*53
# Write temporary image
cv2.imwrite('temp.png', res)
# Open the image with PIL and load it to RGB pixelpoints
mask2 = Image.open('temp.png')
pix = mask2.load()
x,y = mask2.size
# Itearate through the image and make some sort of logic to replace the pixels that
# differs from the mean of the image
# NOTE that this alghorithm is for example and it will not work with other images
for i in range(0,x):
for j in range(0,y):
if -1<pix[i,j][0]<bp or -1<pix[i,j][1]<gp or -1<pix[i,j][2]<rp:
try:
pix[i,j] = b,g,r
except:
pix[i,j] = (int(mean[0]),int(mean[1]),int(mean[2]))
else:
b,g,r = pix[i,j]
# Transform the image back to cv2 format and mask the result
res = np.array(mask2)
res = res[:,:,::-1].copy()
final = cv2.bitwise_and(res, res, mask=mask)
# Display the result
cv2.imshow('img', final)
cv2.waitKey(0)
cv2.destroyAllWindows()
You can try the following steps, at least to get a road map to the proper solution implementation:
Find the hair region using adaptive local thresholding - Otsu's
method or any other method. I think "local thresholding" or even
"local histogram equalization and then global thresholding" will
find the hair regions.
To fill the hair regions, use "texture synthesis" to synthesize skin
like texture for the hair region.
One good and easy method for texture synthesis is described in "A.A. Efros and T.K. Leung, Texture synthesis by non-parametric sampling', In Proceedings of the International Conference on Computer Vision (ICCV), Kerkyra, Greece, 1999".
Texture synthesis will give a better result than averaging or median filtering to estimate the pixels in the hair region.
Also, take a look at this paper, it should help you a lot:
http://link.springer.com/article/10.1007%2Fs00521-012-1149-1?LI=true

Rectangular bounding boxes around objects in monochrome images in python?

I have a set of two monochrome images [attached] where I want to put rectangular bounding boxes for both the persons in each image. I understand that cv2.dilate may help, but most of the examples I see are focusing on detecting one rectangle containing the maximum pixel intensities, so essentially they put one big rectangle in the image. I would like to have two separate rectangles.
UPDATE:
This is my attempt:
import numpy as np
import cv2
im = cv2.imread('splinet.png',0)
print im.shape
kernel = np.ones((50,50),np.uint8)
dilate = cv2.dilate(im,kernel,iterations = 10)
ret,thresh = cv2.threshold(im,127,255,0)
im3,contours, hierarchy = cv2.findContours(thresh,cv2.RETR_TREE,cv2.CHAIN_APPROX_SIMPLE)
plt.imshow(im,cmap='Greys_r')
#plt.imshow(im3,cmap='Greys_r')
for i in range(0, len(contours)):
if (i % 2 == 0):
cnt = contours[i]
#mask = np.zeros(im2.shape,np.uint8)
#cv2.drawContours(mask,[cnt],0,255,-1)
x,y,w,h = cv2.boundingRect(cnt)
cv2.rectangle(im,(x,y),(x+w,y+h),(255,255,0),5)
plt.imshow(im,cmap='Greys_r')
cv2.imwrite(str(i)+'.png', im)
cv2.destroyAllWindows()
And the output is attached below: As you see, small boxes are being made and its not super clear too.
The real problem in your question lies in selection of the optimal threshold from the monochrome image.
In order to do that, calculate the median of the gray scale image (the second image in your post). The threshold level will be set 33% above this median value. Any value below this threshold will be binarized.
This is what I got:
Now performing morphological dilation followed by contour operations you can highlight your region of interest with a rectangle.
Note:
Never set a manual threshold as you did. Threshold can vary for different images. Hence always opt for a threshold based on the median of the image.

Remove background of the image using opencv Python

I have two images, one with only background and the other with background + detectable object (in my case its a car). Below are the images
I am trying to remove the background such that I only have car in the resulting image. Following is the code that with which I am trying to get the desired results
import numpy as np
import cv2
original_image = cv2.imread('IMG1.jpg', cv2.IMREAD_COLOR)
gray_original = cv2.cvtColor(original_image, cv2.COLOR_BGR2GRAY)
background_image = cv2.imread('IMG2.jpg', cv2.IMREAD_COLOR)
gray_background = cv2.cvtColor(background_image, cv2.COLOR_BGR2GRAY)
foreground = np.absolute(gray_original - gray_background)
foreground[foreground > 0] = 255
cv2.imshow('Original Image', foreground)
cv2.waitKey(0)
The resulting image by subtracting the two images is
Here is the problem. The expected resulting image should be a car only.
Also, If you take a deep look in the two images, you'll see that they are not exactly same that is, the camera moved a little so background had been disturbed a little. My question is that with these two images how can I subtract the background. I do not want to use grabCut or backgroundSubtractorMOG algorithm right now because I do not know right now whats going on inside those algorithms.
What I am trying to do is to get the following resulting image
Also if possible, please guide me with a general way of doing this not only in this specific case that is, I have a background in one image and background+object in the second image. What could be the best possible way of doing this. Sorry for such a long question.
I solved your problem using the OpenCV's watershed algorithm. You can find the theory and examples of watershed here.
First I selected several points (markers) to dictate where is the object I want to keep, and where is the background. This step is manual, and can vary a lot from image to image. Also, it requires some repetition until you get the desired result. I suggest using a tool to get the pixel coordinates.
Then I created an empty integer array of zeros, with the size of the car image. And then I assigned some values (1:background, [255,192,128,64]:car_parts) to pixels at marker positions.
NOTE: When I downloaded your image I had to crop it to get the one with the car. After cropping, the image has size of 400x601. This may not be what the size of the image you have, so the markers will be off.
Afterwards I used the watershed algorithm. The 1st input is your image and 2nd input is the marker image (zero everywhere except at marker positions). The result is shown in the image below.
I set all pixels with value greater than 1 to 255 (the car), and the rest (background) to zero. Then I dilated the obtained image with a 3x3 kernel to avoid losing information on the outline of the car. Finally, I used the dilated image as a mask for the original image, using the cv2.bitwise_and() function, and the result lies in the following image:
Here is my code:
import cv2
import numpy as np
import matplotlib.pyplot as plt
# Load the image
img = cv2.imread("/path/to/image.png", 3)
# Create a blank image of zeros (same dimension as img)
# It should be grayscale (1 color channel)
marker = np.zeros_like(img[:,:,0]).astype(np.int32)
# This step is manual. The goal is to find the points
# which create the result we want. I suggest using a
# tool to get the pixel coordinates.
# Dictate the background and set the markers to 1
marker[204][95] = 1
marker[240][137] = 1
marker[245][444] = 1
marker[260][427] = 1
marker[257][378] = 1
marker[217][466] = 1
# Dictate the area of interest
# I used different values for each part of the car (for visibility)
marker[235][370] = 255 # car body
marker[135][294] = 64 # rooftop
marker[190][454] = 64 # rear light
marker[167][458] = 64 # rear wing
marker[205][103] = 128 # front bumper
# rear bumper
marker[225][456] = 128
marker[224][461] = 128
marker[216][461] = 128
# front wheel
marker[225][189] = 192
marker[240][147] = 192
# rear wheel
marker[258][409] = 192
marker[257][391] = 192
marker[254][421] = 192
# Now we have set the markers, we use the watershed
# algorithm to generate a marked image
marked = cv2.watershed(img, marker)
# Plot this one. If it does what we want, proceed;
# otherwise edit your markers and repeat
plt.imshow(marked, cmap='gray')
plt.show()
# Make the background black, and what we want to keep white
marked[marked == 1] = 0
marked[marked > 1] = 255
# Use a kernel to dilate the image, to not lose any detail on the outline
# I used a kernel of 3x3 pixels
kernel = np.ones((3,3),np.uint8)
dilation = cv2.dilate(marked.astype(np.float32), kernel, iterations = 1)
# Plot again to check whether the dilation is according to our needs
# If not, repeat by using a smaller/bigger kernel, or more/less iterations
plt.imshow(dilation, cmap='gray')
plt.show()
# Now apply the mask we created on the initial image
final_img = cv2.bitwise_and(img, img, mask=dilation.astype(np.uint8))
# cv2.imread reads the image as BGR, but matplotlib uses RGB
# BGR to RGB so we can plot the image with accurate colors
b, g, r = cv2.split(final_img)
final_img = cv2.merge([r, g, b])
# Plot the final result
plt.imshow(final_img)
plt.show()
If you have a lot of images you will probably need to create a tool to annotate the markers graphically, or even an algorithm to find markers automatically.
The problem is that you're subtracting arrays of unsigned 8 bit integers. This operation can overflow.
To demonstrate
>>> import numpy as np
>>> a = np.array([[10,10]],dtype=np.uint8)
>>> b = np.array([[11,11]],dtype=np.uint8)
>>> a - b
array([[255, 255]], dtype=uint8)
Since you're using OpenCV, the simplest way to achieve your goal is to use cv2.absdiff().
>>> cv2.absdiff(a,b)
array([[1, 1]], dtype=uint8)
I recommend using OpenCV's grabcut algorithm. You first draw a few lines on the foreground and background, and keep doing this until your foreground is sufficiently separated from the background. It is covered here: https://docs.opencv.org/trunk/d8/d83/tutorial_py_grabcut.html
as well as in this video: https://www.youtube.com/watch?v=kAwxLTDDAwU

Categories