Threshold image using image subtraction using opencv python - python-2.7

Can you anyone tell me how to get threshold image using frame differencing
I have an idea about various background subtraction method but i donot want to use them.
cv2.substract(img1,img2) gives this image
substract:
but i want this result threshold
Can anyone tell me how to do that
i donot want to use cv2.createBackgroundSubtractorMOG2() or such kind function
here is my
import cv2
import numpy as np
t=0.01
background=cv2.imread('background2.png')
cap = cv2.VideoCapture('car.mp4')
ret,img=cap.read()
avg_img = np.float32(img)
while 1:
ret,img=cap.read()
cv2.accumulateWeighted(img,avg_img,0.1)
res1 = cv2.convertScaleAbs(avg_img)
sub_img=cv2.subtract(res1,img)
cv2.imshow('sub_img',sub_img)
cv2.imshow('sub_img',sub_img)
if cv2.waitKey(1) & 0xFF == ord('q'):
break
cap.release()
cv2.destroyAllWindows()
My opencv version 3.0.0 python 2.7

Since you are OK with this being done outside of cv2:
# Subtraction, assuming img1 and img2 are numpy arrays with same dimension; optionally, use np.abs(img1-img2) if you don't care about the sign of the difference
sub = img1 - img2
# Thresholding
threshold = 128 # Set your threshold value
sub[sub >= threshold] = 255 # Above or equal threshold go to max value
sub[sub < threshold] = 0 # Below threshold go to min value

Related

segmentation of overlapping cells

The following python script should split overlapping cells apart which does work quite good. The problem is now that it also splits some of the cells apart which don't overlap with other cells. To make things clear to you i'll add my input image and the output image.
The input:input image
The output:
output image
Output image where I marked two "bad" segmented cells:Output image with marked errors
Thresholded image: Thresholded image
Does someone have an idea how to avoid this problem or is the whole approach not good enough to process these kind of images?
I am using the following piece of code to segment the cells:
from skimage.feature import peak_local_max
from skimage.morphology import watershed
from scipy import ndimage
import numpy as np
import cv2
# load the image and perform pyramid mean shift filtering
# to aid the thresholding step
image = cv2.imread('C:/Users/Root/Desktop/image13.jpg')
shifted = cv2.pyrMeanShiftFiltering(image, 41, 51)
# convert the mean shift image to grayscale, then apply
# Otsu's thresholding
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
thresh = cv2.threshold(gray, 0, 255,
cv2.THRESH_BINARY | cv2.THRESH_OTSU)[1]
im = gray.copy()
D = ndimage.distance_transform_edt(thresh)
localMax = peak_local_max(D, indices=False, min_distance=3,
labels=thresh)
# perform a connected component analysis on the local peaks,
# using 8-connectivity, then apply the Watershed algorithm
markers = ndimage.label(localMax, structure=np.ones((3, 3)))[0]
labels = watershed(-D, markers, mask=thresh)
print("[INFO] {} unique segments found".format(len(np.unique(labels)) - 1))
conts=[]
for label in np.unique(labels):
# if the label is zero, we are examining the 'background'
# so simply ignore it
if label == 0:
continue
# otherwise, allocate memory for the label region and draw
# it on the mask
mask = np.zeros(gray.shape, dtype="uint8")
mask[labels == label] = 255
# detect contours in the mask and grab the largest one
cnts = cv2.findContours(mask.copy(), cv2.RETR_EXTERNAL,
cv2.CHAIN_APPROX_SIMPLE)[-2]
c = max(cnts, key=cv2.contourArea)
rect = cv2.minAreaRect(c)
box = cv2.boxPoints(rect)
box = np.int0(box)
if cv2.contourArea(c) > 150:
#cv2.drawContours(image,c,-1,(0,255,0))
cv2.drawContours(image,[box],-1,(0,255,0))
cv2.imshow("output", image)
cv2.waitKey()

When I threshold an image I get a completely black image

I am attempting to threshold a wave so that the white background appears black and the wave itself which was originally black is white, however it only seems to return an entirely black image. What am I doing wrong?
import cv2
src = cv2.imread("C:\\Users\\ksatt\\Desktop\\SoundByte\\blackwaveblackaxis (1).PNG",0)
maxValue = 255
thresh= 53
if not src is None:
th, dst = cv2.threshold(src, thresh, maxValue, cv2.THRESH_BINARY_INV)
cv2.imshow("blackwave.PNG", dst)
cv2.imwrite("blackwave.PNG", dst)
cv2.waitKey(0)
else:
print 'Image could not be read'
Your threshold is too low, and the dark paper is going to pick up values that you don't want anyways. Basically, the contrast of the image is too low.
One easy solution is to subtract out the background. The simple way to do this is to dilate() your grayscale image, which will expand the white area and overtake the black lines. Then you can apply a small GaussianBlur() to that dilated image, and this will give you a "background" image that you can subtract from your original image to get a clear view of the lines. From there you'll have a much better image to threshold(), and you can even use OTSU thresholding to automatically set the threshold level for you.
import cv2
import numpy as np
# read image
src = cv2.imread('wave.png',0)
# create background image
bg = cv2.dilate(src, np.ones((5,5), dtype=np.uint8))
bg = cv2.GaussianBlur(bg, (5,5), 1)
# subtract out background from source
src_no_bg = 255 - cv2.absdiff(src, bg)
# threshold
maxValue = 255
thresh = 240
retval, dst = cv2.threshold(src_no_bg, thresh, maxValue, cv2.THRESH_BINARY_INV)
# automatic / OTSU threshold
retval, dst = cv2.threshold(src_no_bg, 0, maxValue, cv2.THRESH_BINARY_INV+cv2.THRESH_OTSU)
You can see that manual thresholding gives the same results as OTSU, but you don't have to play around with the values for OTSU, it'll find them for you. This isn't always the best way to go but it can be quick sometimes. Check out this tutorial for more on different thresholding operations.
if you take a look at http://docs.opencv.org/2.4/modules/imgproc/doc/miscellaneous_transformations.html#threshold it will tell you what each parameter does of the function.
Also here is a good tutorial:
http://docs.opencv.org/trunk/d7/d4d/tutorial_py_thresholding.html
Python: cv.Threshold(src, dst, threshold, maxValue, thresholdType) →
None
Is the prototype which gets further explenation in the mentioned API.
So simply change your code to:
cv2.threshold(src,RESULT, thresh, maxValue, cv2.THRESH_BINARY_INV)
cv2.imshow("blackwave.PNG", RESULT)
Could you post a picture of the wave? Have you tried using standard python? Something like this should work:
import numpy as np
import matplotlib.pyplot as plt
maxValue = 255
thresh= 53
A = np.load('file.png')
# For each pixel, see if it's above/below the threshold
for i in range(A.shape[0]): # Loop along the X direction
for j in range(A.shape[1]): # Loop along the Y direction
# Set to black the background
if A[i,j] > thresh:
A[i,j] = 0
if A[i,j] == 0:
A[i,j] = 255
Or something similar.

Poor Performance and Strange Array Behavior when run on Linux

So I am working on a script to do some video processing. It will read a video file searching for red dots that are a certain size then find the center of each and return the x/y coordinates. Initially I had it working great on my Windows Machine, so I sent it over to the raspberry pi to see if i would encounter issues, and boy did I.
On Windows the script would run in real time, completing at the same time as the video. On the Raspberry it is slowwwwwwww. Also I noticed when I looked into the structure of countours, there is a huge array of 0's first, before my x/y coordinates array. I have no idea what is creating this, but it doesn't happen on the windows box.
I have same version of python and opencv installed on both boxes, the only difference is numpy 1.11 on windows and numpy 1.12 on raspberry. Note, I had to change np.mean(contours[?]) to 1 to skip the initial array of 0's. What have I done wrong?
Here's a video I made for testing purposes if needed:
http://www.foxcreekwinery.com/video.mp4
import numpy as np
import cv2
def vidToPoints():
cap = cv2.VideoCapture('video.mp4')
while(cap.isOpened()):
ret, image = cap.read()
if (ret):
cv2.imshow('frame',image)
if cv2.waitKey(1) == ord('q'):
break
# save frame as image
cv2.imwrite('frame.jpg',image)
# load the image
image = cv2.imread('frame.jpg')
# define the list of boundaries
boundaries = [
([0, 0, 150], [90, 90, 255])
]
# loop over the boundaries
for (lower, upper) in boundaries:
# create NumPy arrays from the boundaries
lower = np.array(lower, dtype = "uint8")
upper = np.array(upper, dtype = "uint8")
# find the colors within the specified boundaries
mask = cv2.inRange(image, lower, upper)
if (50 > cv2.countNonZero(mask) > 10):
#find contour
contours = cv2.findContours(mask, 0, 1)
#average countour list to find center
avg = np.mean(contours[1],axis=1)
x = int(round(avg[0,0,0]))
y = int(round(avg[0,0,1]))
print [x,y]
print cv2.countNonZero(mask)
for l in range(5):
cap.grab()
else:
break
cap.release()
cv2.destroyAllWindows()
vidToPoints()

Python OpenCv2, counting contours of colored object

I want to be able to count the number of pixels in a detected object. I'm using the cv2.threshold function. Here is some sudo code.
import cv2
import numpy as np
import time
while True:
cam= cv2.VideoCapture(0)
while(cam.isOpened())
ret, image = cam.read()
image = cv2.GaussianBlur(image, (5,5), 0)
Image1 = cv2.cvtColor(image, cv2.COLOR_BGR2HSV)
lower= np.array([30,40,40], dtype='uint8')
upper= np.array([95,240,240], dtype='uint8')
Thresh= cv2.inRange(Image1, lower, upper)
From here on out, I have no idea how to count the pixels of my objects. How do you find the contours of a binary image? I suppose it could be possible to cv2.bitwise_and a full black image over the Thresh/ mask, but that seems like it could be slow and also I don't know how to create a fully black and white image like that.
So TD:LR, how do you count the number of pixels in an object from a binary image?
Note: I'm actually just after the largest object and only need the number of pixels, not the image.
Edit: not trying to count the total number of pixels detected, I've already done that. Want the number of pixels detected from the object with the largest number.
This is how I did it
import cv2
import numpy as np
import time
from scipy.ndimage import (labeled_comprehension, label, measurements, generate_binary_structure) # new import
while True:
cam= cv2.VideoCapture(0)
while(cam.isOpened())
ret, image = cam.read() # record image
image = cv2.GaussianBlur(image, (5,5), 0) # blur to remove noise
Image1 = cv2.cvtColor(image, cv2.COLOR_BGR2HSV) # convert to better color scheme
lower= np.array([30,40,40], dtype='uint8') # low green
upper= np.array([95,240,240], dtype='uint8') # high green
Thresh= cv2.inRange(Image1, lower, upper) # returns array with 255 as pixel if in threshold
struct = generate_binary_structure(2,2) # seems necessary for some reason
Label, features = label(Thresh, struct) # label is object, features is number of objects
Arange = np.arange(1, features+1) # seems necessary for some reason
Biggest = sorted(labeled_comprehension(Thresh, Label, Arange, np.sum, float, -1))[features-1]//255 # counts and organises the objects based on size. [features-1] means last object, ie: biggest. //255 because that's each pixel work (from thresh)

OpenCV edge enhancement

I am performing background subtraction to obtain a moving car from a video as below ( Running average background modeling)
I am applying findContours() after this to draw a polygon around the car.
As you can see, the quality of the obtained output is not great. Is there any way I can enhance the edges of the car to make it more prominent and cut out the extraneous noise surrounding it. I tried performing morphological closing(dilate -> erode) to fill the gaps, but the output was not as expected.
This might be overkill and far from a quick solution but Level Set Methods would be very suited to extract the presegmented car.
You can try to apply background subtraction by using cv2.createBackgroundSubtractorMOG2().
Code:
import cv2
import numpy as np
cap = cv2.VideoCapture(0)
out = cv2.createBackgroundSubtractorMOG2()
fourcc = cv2.VideoWriter_fourcc(*'MJPG')
output = cv2.VideoWriter('output.avi', fourcc, 20.0, (640,480), isColor=False)
while(cap.isOpened()):
ret, frame = cap.read()
if ret==True:
frame = cv2.flip(frame,180)
outmask = out.apply(frame)
output.write(outmask)
cv2.imshow('original', frame)
cv2.imshow('Motion Tracker', outmask)
if cv2.waitKey(1) & 0xFF == ord('q'):
break
else:
break
output.release()
cap.release()
cv2.destroyAllWindows()