Finding Variance of an image in OpenCV -Python - python

I am trying to find the variance of a greyscale image in OpenCV -Python. I first take the image read in and split it into sub-images, I want to calculate the variance of these sub-images (cropped_img).
I'm not sure how to calculate variance in python, I assumed that I could calculate the covariance matrix to find the variance using the rule:
Var(X) = Cov(X,X)
The thing is I can't get my head around how to use cv2.calcCovarMatrix(), and I can't find any examples in python.
I did find this example in C++ but I have never used the language and im struggling to convert it into python: calcCovarMatrix in multichannel image and unresolved assertion error
Here is my code:
#import packages
import numpy as np
import cv2
#Read in image as grey-scale
img = cv2.imread('images/0021.jpg', 0)
#Set scale of grid
scale = 9
#Get x and y components of image
y_len,x_len = img.shape
covar = []
for y in range(scale):
for x in range(scale):
#Crop image 9*9 windows
cropped_img=img[(y*y_len)/scale:((y+1)*y_len)/scale,
(x*x_len)/scale:((x+1)*x_len)/scale]
#Here is where I need to calc variance
cv2.calcCovarMatrix(cropped_img, covar, meanBGR, cv2.cv.CV_COVAR_NORMAL)
#???
cropped_img[:] = covar
cv2.imshow('output_var',img)
cv2.waitKey(0)
cv2.destroyAllWindows()
If anyone has any ideas or if you have a better way to calculate variance then I would be extremely grateful.
Thanks.
EDIT: I also found this example in c; mean and variance of image in single pass, but it doesn't seem too efficient.

To get the variance of gray scale image in python you can use numpy.
import numpy as np
var = np.var(img)

Related

Using perspective transformation to change point of view of an image. Not getting desired result

I am trying to change the perspective of the first image according to the second image. For finding the homography matrix I have found the four coordinates of a common object(white notice board) in both images.
Image 1
Image 2
import numpy as np
import matplotlib.pyplot as plt
import matplotlib
img1 = cv2.imread("rgb per.jpg")
img2 = cv2.imread("IR per.jpg")
img_1_coor = np.float32([[1178,425], [1201,425], [1178,439], [1201,439], [1551,778]]) #coordinate of white notice board in rgb image
img_2_coor = np.float32([[370,98], [381,103], [367,107], [380,112], [498,332]]) #coordinate of same object in IR image
for x in range(0,4):
cv2.circle(img1,(img_1_coor[x][0],img_1_coor[x][1]),5,(255,0,0),1)
matplotlib.rcParams['figure.dpi'] = 300
#plt.imshow(img1) #this verified that the found coordinates are correct
#P = cv2.getPerspectiveTransform(img_1_coor,img_2_coor)
H, s = cv2.findHomography (img_1_coor,img_2_coor)
print(s)
perspective = cv2.warpPerspective(img1, H, img2.shape[:2])
plt.imshow(perspective)
#the resulting image
Output image
I want the output to be like image 1 with point-of-view(camera angle) as image 2. If this is not possible, vice versa would also be helpful to have image 2 with the point of view as image 1.
Can someone tell if it's possible to use coordinates of the object in image to change the perspective of full-image, if yes is there any problem with my code?
I recommend a computer vision package that implements the perspective transform (e.g. OpenCV or whatever they use nowadays). It is a fairly common computer vision operation. It is also known less properly as corner-pinning.
If you wish to implement it yourself as an exercise, you may look at the Direct Linear Transform where you solve your matrix problem in homogenous coordinates, possibly by using a singular value decomposition.

What is the difference between opencv ximgproc.slic and skimage segmentation.slic?

I run the SLIC (Simple Linear Iterative Clustering) superpixels algorithm from opencv and skimage on the same picture with, but got different results, the skimage slic result is better, Shown in the picture below.First one is opencv SLIC, the second one is skimage SLIC. I got several questions hope someonc can help.
Why opencv have the parameter 'region_size' while skimage is 'n_segments'?
Is convert to LAB and a guassian blur necessary?
Is there any trick to optimize the opecv SLIC result?
===================================
OpenCV SLIC
Skimage SLIC
# Opencv
src = cv2.imread('pic.jpg') #read image
# gaussian blur
src = cv2.GaussianBlur(src,(5,5),0)
# Convert to LAB
src_lab = cv.cvtColor(src,cv.COLOR_BGR2LAB) # convert to LAB
# SLIC
cv_slic = ximg.createSuperpixelSLIC(src_lab,algorithm = ximg.SLICO,
region_size = 32)
cv_slic.iterate()
# Skimage
src = io.imread('pic.jpg')
sk_slic = skimage.segmentation.slic(src,n_segments = 256, sigma = 5)
Image with superpixels centroid generated with the code below
# Measure properties of labeled image regions
regions = regionprops(labels)
# Scatter centroid of each superpixel
plt.scatter([x.centroid[1] for x in regions], [y.centroid[0] for y in regions],c = 'red')
but there is one superpixel less(top-left corner), and I found that
len(regions) is 64 while len(np.unique(labels)) is 65 , why?
I'm not sure why you think skimage slic is better (and I maintain skimage! 😂), but:
different parameterizations are common in mathematics and computer science. Whether you use region size or number of segments, you should get the same result. I expect the formula to convert between the two will be something like n_segments = image.size / region_size.
The original paper suggests that for natural images (meaning images of the real world like you showed, rather than e.g. images from a microscope or from astronomy), converting to Lab gives better results.
to me, based on your results, it looks like the gaussian blur used for scikit-image was higher than for openCV. So you could make the results more similar by playing with the sigma. I also think the compactness parameter is probably not identical between the two.

Python: Normalize image exposure

I'm working on a project to measure and visualize image similarity. The images in my dataset come from photographs of images in books, some of which have very high or low exposure rates. For example, the images below come from two different books; the one on the top is an over-exposed reprint of the one on the bottom, wherein the exposure looks good:
I'd like to normalize each image's exposure in Python. I thought I could do so with the following naive approach, which attempts to center each pixel value between 0 and 255:
from scipy.ndimage import imread
import sys
def normalize(img):
'''
Normalize the exposure of an image.
#args:
{numpy.ndarray} img: an array of image pixels with shape:
(height, width)
#returns:
{numpy.ndarray} an image with shape of `img` wherein
all values are normalized such that the min=0 and max=255
'''
_min = img.min()
_max = img.max()
return img - _min * 255 / (_max - _min)
img = imread(sys.argv[1])
normalized = normalize(img)
Only after running this did I realize that this normalization will only help images whose lightest value is less than 255 or whose darkest value is greater than 0.
Is there a straightforward way to normalize the exposure of an image such as the top image above? I'd be grateful for any thoughts others can offer on this question.
Histogram equalisation works surprisingly well for this kind of thing. It's usually better for photographic images, but it's helpful even on line art, as long as there are some non-black/white pixels.
It works well for colour images too: split the bands up, equalize each one separately, and recombine.
I tried on your sample image:
Using libvips:
$ vips hist_equal sample.jpg x.jpg
Or from Python with pyvips:
x = pyvips.Image.new_from_file("sample.jpg")
x = x.hist_equal()
x.write_to_file("x.jpg")
It's very hard to say if it will work for you without seeing a larger sample of your images, but you may find an "auto-gamma" useful. There is one built into ImageMagick and the description - so that you can calculate it yourself - is:
Automagically adjust gamma level of image.
This calculates the mean values of an image, then applies a calculated
-gamma adjustment so that the mean color in the image will get a value of 50%.
This means that any solid 'gray' image becomes 50% gray.
This works well for real-life images with little or no extreme dark
and light areas, but tend to fail for images with large amounts of
bright sky or dark shadows. It also does not work well for diagrams or
cartoon like images.
You can try it out yourself on the command line very simply before you go and spend a lot of time coding something that may not work:
convert Tribunal.jpg -auto-gamma result.png
You can do -auto-level as per your own code beforehand, and a thousand other things too:
convert Tribunal.jpg -auto-level -auto-gamma result.png
I ended up using a numpy implementation of the histogram normalization method #user894763 pointed out. Just save the below as normalize.py then you can call:
python normalize.py cats.jpg
Script:
import numpy as np
from scipy.misc import imsave
from scipy.ndimage import imread
import sys
def get_histogram(img):
'''
calculate the normalized histogram of an image
'''
height, width = img.shape
hist = [0.0] * 256
for i in range(height):
for j in range(width):
hist[img[i, j]]+=1
return np.array(hist)/(height*width)
def get_cumulative_sums(hist):
'''
find the cumulative sum of a numpy array
'''
return [sum(hist[:i+1]) for i in range(len(hist))]
def normalize_histogram(img):
# calculate the image histogram
hist = get_histogram(img)
# get the cumulative distribution function
cdf = np.array(get_cumulative_sums(hist))
# determine the normalization values for each unit of the cdf
sk = np.uint8(255 * cdf)
# normalize the normalization values
height, width = img.shape
Y = np.zeros_like(img)
for i in range(0, height):
for j in range(0, width):
Y[i, j] = sk[img[i, j]]
# optionally, get the new histogram for comparison
new_hist = get_histogram(Y)
# return the transformed image
return Y
img = imread(sys.argv[1])
normalized = normalize_histogram(img)
imsave(sys.argv[1] + '-normalized.jpg', normalized)
Output:

how to find the pca of an image using python and opencv?

I am developing an image classifier using svm.In the feature extraction phase can i use pca as feature.How to find the pca of an image using python and opencv.what my plan is
Find pca of each image in training set and store it in a array.It may be list of lists
Store class labels in another list
pass this as argument to svm
Am i going in right Direction.Please help me
Yes you can do PCA+SVM, some might argue that PCA is not the best feature to use or SVM is not the best classification algorithm. But hey, have a good start is better than sitting around.
To do PCA with OpenCV, try something like (I haven't verified the codes, just to get you an idea):
import os
import cv2
import numpy as np
# Construct the input matrix
in_matrix = None
for f in os.listdir('dirpath'):
# Read the image in as a gray level image. Some modifications
# of the codes are needed if you want to read it in as a color
# image. For simplicity, let's use gray level images for now.
im = cv2.imread(os.path.join('dirpath', f), cv2.IMREAD_GRAYSCALE)
# Assume your images are all the same size, width w, and height h.
# If not, let's resize them to w * h first with cv2.resize(..)
vec = im.reshape(w * h)
# stack them up to form the matrix
try:
in_matrix = np.vstack((in_matrix, vec))
except:
in_matrix = vec
# PCA
if in_matrix is not None:
mean, eigenvectors = cv2.PCACompute(in_matrix, np.mean(in_matrix, axis=0).reshape(1,-1))

Finding square centers from a picture

After an Image Processing, from fft's, filters, and thresholding, I obtained the following image:
So, I'm wondering how to extract those centers. Does exist any function from OpenCV? (such as HoughCircles for detecting circles?) or Do I need to use clustering methods?
Maybe it is useful for you to know the code I used:
import cv2
import numpy as np
import scipy.ndimage as ndimage
from scipy.ndimage import maximum_filter
img = cv2.imread("pic.tif",0)
s = np.fft.fftshift(np.fft.fft2(img))
intensity = 20 * np.log(np.abs(s))
maxs = maximum_filter(intensity, 125)
maxs[maxs < intensity] = intensity.max()
ret, thresh = cv2.threshold(maxs.astype('uint8'),0,255,cv2.THRESH_BINARY_INV+cv2.THRESH_OTSU)
imshow(thresh)
PS: So I have another question, it could be useful for some of you. The maximum_filter function gave me the "3 squares"(then I'll get a better visualization of them by using thresholding), so is there a way to use the maximum_filter function and to obtain "3 circles"? Then we can use HoughCircles to obtain the 3 centers circles.
You may need to use Image Moments.
As the pre-processing steps, threshold the source to create mask of squares, and then pass to findcontours.

Categories