Getting mean of an image using a mask - python-2.7

I have a series of concentric rectangles and wish to obtain the means of the outer rectangle excluding the inner rectangle. See the attached diagram , I need to get the mean for the shaded area.
So I am using a mask of the inner rectangle to pass into the cv2.mean method, but I am not sure how to set the mask. I have the following code:
for i in xrange(0,len(wins)-2,1):
means_1 = cv2.mean(wins[i])[0]
msk = cv2.bitwise_and(np.ones_like((wins[i+1]), np.uint8),np.zeros_like((wins[i]), np.uint8))
means_2 = cv2.mean(wins[i+1],mask=msk)
means_3 = cv2.mean(wins[i+1])[0]
print means_1,means_2,means_3
I get this error for the means_2 (means_3 works fine).:
error:
/Users/jenkins/miniconda/0/2.7/conda-bld/work/opencv-2.4.11/modules/core/src/arithm.cpp:1021:
error: (-209) The operation is neither 'array op array' (where arrays
have the same size and type), nor 'array op scalar', nor 'scalar op
array' in function binary_op

The mask here refers to a binary mask which has 0 as background and 255 as foreground, So You need to create an empty mask with default color = 0 and then paint the Region of Interest where you want to find the mean with 255. Suppose I have input image [512 x 512]:
Lets's assume 2 concentric rectangles as:
outer_rect = [100, 100, 400, 400] # top, left, bottom, right
inner_rect = [200, 200, 300, 300]
Now create the binary mask using these rectangles as:
mask = np.zeros(image.shape[:2], dtype=np.uint8)
cv2.rectangle(mask, (outer_rect[0], outer_rect[1]), (outer_rect[2], outer_rect[3]), 255, -1)
cv2.rectangle(mask, (inner_rect[0], inner_rect[1]), (inner_rect[2], inner_rect[3]), 0, -1)
Now you may call the cv2.mean() to get the mean of foreground area, labelled with 255 as:
lena_mean = cv2.mean(image, mask)
>>> (109.98813432835821, 96.60768656716418, 173.57567164179105, 0.0)

In Python/OpenCV or any software, if you have a masked image and the binary mask, then the mean of the non-black pixels in the image (i.e. ROI) is the mean of the masked image divided by the mean of the mask
Input:
Mask:
import cv2
import numpy as np
# load image
img = cv2.imread('lena_g.png', cv2.IMREAD_GRAYSCALE)
# load mask
mask = cv2.imread('lena_mask.png', cv2.IMREAD_GRAYSCALE)
# compute means
mean_img = np.mean(img)
mean_mask = np.mean(mask)
# compute 255*mean_img/mean_mask
mean_roi = 255 * mean_img / mean_mask
# print mean of each
print("mean of image:", mean_img)
print("mean of mask:", mean_mask)
print("mean of roi:", mean_roi)
mean of image: 98.50196838378906
mean of mask: 216.090087890625
mean of roi: 116.23856597522328

Related

OpenCV Python: How to warpPerspective a large image based on transform inferred from small region

I am using cv2.getPerspectiveTransform() and cv2.warpPerspective() to warp an image according to Adrian Rosenbrock blog : https://www.pyimagesearch.com/2014/08...
However in my case I have an image where I can only select the region B to be warped but need to warp (top-down view) the whole larger image A.
Can the parameters of the perspective transform inferred from the smaller region B be applied to the full image A? Is that possible?enter image description here
Here is one way to demonstrate that the matrix from the red square applies to the whole image in Python OpenCV.
Here I rectify the quadrilateral into a rectangle on the basis of its top and left dimensions.
Input:
import numpy as np
import cv2
import math
# read input
img = cv2.imread("red_quadrilateral.png")
hh, ww = img.shape[:2]
# specify input coordinates for corners of red quadrilateral in order TL, TR, BR, BL as x,
input = np.float32([[136,113], [206,130], [173,207], [132,196]])
# get top and left dimensions and set to output dimensions of red rectangle
width = round(math.hypot(input[0,0]-input[1,0], input[0,1]-input[1,1]))
height = round(math.hypot(input[0,0]-input[3,0], input[0,1]-input[3,1]))
print("width:",width, "height:",height)
# set upper left coordinates for output rectangle
x = input[0,0]
y = input[0,1]
# specify output coordinates for corners of red quadrilateral in order TL, TR, BR, BL as x,
output = np.float32([[x,y], [x+width-1,y], [x+width-1,y+height-1], [x,y+height-1]])
# compute perspective matrix
matrix = cv2.getPerspectiveTransform(input,output)
print(matrix)
# do perspective transformation setting area outside input to black
# Note that output size is the same as the input image size
imgOutput = cv2.warpPerspective(img, matrix, (ww,hh), cv2.INTER_LINEAR, borderMode=cv2.BORDER_CONSTANT, borderValue=(0,0,0))
# save the warped output
cv2.imwrite("red_quadrilateral_warped.jpg", imgOutput)
# show the result
cv2.imshow("result", imgOutput)
cv2.waitKey(0)
cv2.destroyAllWindows()

algorithm that finds the "mean positioned" white pixel in a column and repeats the process for each column

I am attempting to create an algorithm that locates the white pixels in a column of a binary image, and then adds the y co-ordinates/column number of each white pixel and divides this value by the number of white pixels in the column, in order to get the "mean/middle positioned" white pixel in the column. And this returns an (x,y) co-ordinate that can be plotted. This process repeats for each column in the image and each time sy sets back to 0.
The end goal is instead of having a lines that are multiple pixels thick/wide, as shown in the image's numpy arraycurrent line multiple thicks wide array, I have lines that are just one pixel wide, whilst mantaining the original shape. I planned on doing this by selecting the "mean positioned white pixel in each column". I will then use these pixels to obtain x and y co-ordinates to plot.
Here is what I have
sx = x = img.shape[1]
sy = 0
whitec = cv2.countNonZero(img.shape[1])
arrayOfMeanY = [] #array to place (x,y) co-ordinate in
#Select column to iterate
for x in range(img.shape[1]):
# iterating through individual items in the column
for y in range(img.shape[0]):
# Checking for white pixels
pixel = img[x,y]
if pixel == 255:
# Then we check the y values of the white pixels in the column and add them all up
sy = sy+y
whitec +=1
# Doing the calculation for the mean and putting it into the meanY list
sy = sy/whitec
y = sy
print img[x,y]
array.append(y)
cv2.waitKey(0)
# reset sy to 0 for the next column
sy = 0
My issue is I recieve this error when I run the code:
File "<ipython-input-6-e4c2225ff632>", line 27, in <module>
whitec = cv2.countNonZero(img.shape[1]) #n= number of white pixels
in the column
TypeError: src is not a numpy array, neither a scalar
How do I rectify this issue, and once once this issue is rectified will my coding do what I described above.
No need for loops here. With numpy you hardly ever need to loop over individual pixels.
Instead, create a function which takes the mean of the locations of the non-zero pixels for each column (I converted to np.intp to index the image; you could just cast with int() but np.intp is what Numpy uses for indexing arrays so, it's slightly more appropriate).
def avgWhiteLocOverCol(col):
return np.intp(np.mean(np.where(col)))
Then you can simply apply the function along all columns with np.apply_along_axis().
avgRows = np.apply_along_axis(avgWhiteLocOverCol, 0, img)
For example, let's create an image with white pixels on the middle row and on the diagonal:
import numpy as np
import cv2
img = np.eye(500)*255
img[249,:] = 255
cv2.imshow('',img)
cv2.waitKey(0)
Then we can apply the function over each column, which should give a line with half the slope:
def avgWhiteLocOverCol(col):
return int(np.mean(np.where(col)))
avgRows = np.apply_along_axis(avgWhiteLocOverCol, 0, img)
avgIndImg = np.zeros_like(img)
avgIndImg[avgRows,range(img.shape[1])] = 255
cv2.imshow('',avgIndImg)
cv2.waitKey(0)

checking the Colors Opencv Python

I have a code to detect two colors green and blue. I want to check if
green color is detected to print a massage and if blue color is detected to print another message too
Here is the Code:
import cv2
import numpy as np
cap = cv2.VideoCapture(0)
while(1):
# Take each frame
_, frame = cap.read()
# Convert BGR to HSV
hsv = cv2.cvtColor(frame, cv2.COLOR_BGR2HSV)
# define range of blue color in HSV
lower_blue = np.array([110,50,50])
upper_blue = np.array([130,255,255])
lower_green = np.array([50, 50, 120])
upper_green = np.array([70, 255, 255])
green_mask = cv2.inRange(hsv, lower_green, upper_green) # I have the Green threshold image.
# Threshold the HSV image to get only blue colors
blue_mask = cv2.inRange(hsv, lower_blue, upper_blue)
mask = blue_mask + green_mask
############this is the Error ####################
if mask==green_mask:
print "DOne"
################################################
# Bitwise-AND mask and original image
res = cv2.bitwise_and(frame,frame, mask= mask)
cv2.imshow('frame',frame)
cv2.imshow('mask',mask)
cv2.imshow('res',res)
k = cv2.waitKey(5) & 0xFF
if k == 27:
break
cv2.destroyAllWindows()
Running the above code gives me following error:
if mask==green_mask:
ValueError: The truth value of an array with more
than one element is ambiguous. Use a.any() or a.all()
Any ideas how to fix this?
On comparing if mask==green_mask returns an array of boolean value of their dimension which can not satisfy an if condition which require a single boolean.
You need to use a function which will return true if matrix mask and green_mask are all same and return false otherwise. That function should be called under this if condition.
Edit:
Replace the code with
if np.array_equal(mask, green_mask):
It will fix your issue.

Python OpenCV get bottom most value of mask

I have an image from which I extract a colour into a mask as shown in the code below. The mask gives a black and white image. White being the colour I detect. The pixel value of white is 255 and black is 0.
I want to get the bottommost x and Y pixel of the white portion of the mask. How do I do this?
My code is as follows:
image = cv2.imread(FILENAME)
# THE COLOURS ARE IN RGB
lower_blue = np.array([50, 0, 0])
upper_blue = np.array([255, 50, 50])
# loop over the boundaries
# for (lower, upper) in boundaries:
# create NumPy arrays from the boundaries
lower = np.array(lower_blue, dtype = "uint8")
upper = np.array(upper_blue, dtype = "uint8")
# find the colors within the specified boundaries and apply
# the mask
mask = cv2.inRange(image, lower, upper)
you can use numpy's where to search your mask for a specific value:
np.max(np.where(np.max(img_binary,axis=1)==255)

Transform Rectangle to trapezoid for perspective

I have picture from front-view. and I want to turn this into bird's eye view.
Now I want to calculate for each point in the rectangle (x,y) what will be transformed x,y in the trapezoid.
there must be a formula for this transformation with a given x and y and also the angle of the trapezoid (a).
I am programming in C and using opencv.
Thanks a lot in advance.
Did you consider the homography transform. You use this to create or correct perspective in an image, I think that it is exactly what you want.
With OpenCV, you can use the method cv::findHomography(). The arguments are the 4 initial points (vertices of your rectangle) and the 4 final points (the vertices of the trapeze). You get a transformation matrix that you can then use with cv::warpPerspective() or cv::perspectiveTransform().
I was able to figure out a way for your problem.
Here is the code I used for the same:
Importing the required packages:
import cv2
import numpy as np
Reading the image to be used:
filename = '1.jpg'
img = cv2.imread(filename)
cv2.imwrite('img.jpg',img)
Storing the height and width of the image in separate variables:
ih, iw, _ = img.shape
Creating a black window whose size is bigger than that of the image and storing its height and width in separate variables:
black = np.zeros((ih + 300, iw + 300, 3), np.uint8)
cv2.imwrite('black.jpg',black)
bh, bw, _ = black.shape
Storing the 4 corner points of the image in an array:
pts_src = np.array([[0.0, 0.0],[float(iw), 0.0],[float(iw), float(ih)],[0.0,float(ih)]])
Storing the 4 corner points of the trapezoid to be obtained:
pts_dst = np.array([[bw * 0.25, 0],[bw * 0.75, 0.0],[float(bw), float(bh)],[0.0,float(bh)]])
Calculating the homography matrix using pts_src and pts_dst:
h, status = cv2.findHomography(pts_src, pts_dst)
Warping the given rectangular image into the trapezoid:
im_out = cv2.warpPerspective(img, h, (black.shape[1],black.shape[0]))
cv2.imwrite("im_outImage.jpg", im_out)
cv2.waitKey(0)
cv2.destroyAllWindows()
If you alter the values in the array pts_dst you will be able to get different kinds of quadrilaterals.