digital image processing, phyton

profileAssascreed
Subject06_ColorTheory.docx

29 March 2021

In this lecture, you will learn the following:

1. How to display RGB colors in the CIE XYZ color space

2. How to convert from additive RGB color space to subtractive CMY color space

3. How to convert between RGB and HSV color spaces

4. How to convert between RGB and YCbCr (YUV) color spaces

5. Fourier analysis of YUV color bands

# import necessary packages # reading/writing image files

from skimage import io

from skimage import color

# displaying images and plots

import matplotlib.pyplot as plt

# array operations

import numpy as np

# mathematical calculations

import math

# DFT calculations

from scipy import fftpack as ft

# histogram calculation

from skimage import exposure

# signal processing operations

from scipy import signal

from scipy.linalg import circulant

In [66]:

Part 1: Displaying RGB colors in the CIE XYZ color space

# 1. Construct and display the RGB triangle in the CIE XYZ Color Gamut # set CIE XYZ image size

N = 256

# create an empty image to store the color gamut

img_cie_gamut = np.zeros((N,N,3))

# define transformation matrix

rgb2xyz = np.array([[0.449941, 0.316877, 0.181278],

[ 0.244768, 0.673364, 0.081868],

[ 0.025197, 0.141463, 0.906392]])

# go over all RGB colors (use steps of 4 to run faster)

step = 4

for R in range(0,256,step):

for G in range(0,256,step):

for B in range(0,256,step):

if R == 0 and B == 0 and G == 0: continue

RGB = np.array([R,G,B]) XYZ = np.dot(rgb2xyz,RGB)

X = XYZ[0] Y = XYZ[1] Z = XYZ[2]

S = X+Y+Z

x = X/S y = Y/S

x_int = min(int(np.round(x*256,0)),255) y_int = min(int(np.round(y*256,0)),255)

img_cie_gamut[y_int,x_int] = RGB

In [67]:

# end of loops

# set type as byte

img_cie_gamut = img_cie_gamut.astype('uint8')

# draw a diagonal line on the image

for n in range(N): img_cie_gamut[n,N-n-1] = 255

# flip the y axis

img_cie_gamut[:,:,:] = img_cie_gamut[-1::-1,:,:]

# display CIE-XYZ color gamut for RGB primaries

plt.imshow(img_cie_gamut) plt.title('CIE-XYZ Color Gamut') plt.xticks([]), plt.yticks([])

plt.xlabel('x'), plt.ylabel('y') plt.show()

Part 2: Additive RGB Space vs. Subtractive CMY Space

# 2.1 RGB color space and the additive color system # set image size

N =256

# create an empty image to store the colors

img_RGB_colors = np.zeros((N,N,3),dtype=int)

# fill the color image

for n in range(N):

for m in range(N-n):

# find coefficient BG coeff_BG = (float(n)/float(N)) # find coefficient BR

coeff_BR = (float(m)/float(N-n))

# calculate additive color

val_G = coeff_BG

val_R = (1.0-coeff_BG)*coeff_BR val_B = (1.0-coeff_BG)*(1.0-coeff_BR)

# find largest

val_max = max(val_R, val_G, val_B)

# scale so that largest is 1

val_G /= val_max val_R /= val_max val_B /= val_max

# scale to 255

color_G = int(255*val_G) color_R = int(255*val_R) color_B = int(255*val_B)

# set image value

img_RGB_colors[n,m] = np.array([color_R,color_G,color_B])

In [68]:

# flip the y axis

img_RGB_colors[:,:,:] = img_RGB_colors[-1::-1,:,:]

# display color image plt.imshow(img_RGB_colors) plt.title('RGB Additive Color System') plt.xticks([]), plt.yticks([]) plt.show()

In [69]:

# 2.2 CMY color space and the subractive color system

# set image size

N =256

# create full white image to store the colors img_CMY_colors = np.ones((N,N,3),dtype=int) img_CMY_colors *= 255

# fill the color image

for n in range(N):

for m in range(N-n):

# find coefficient BG coeff_BG = (float(n)/float(N)) # find coefficient BR

coeff_BR = (float(m)/float(N-n))

# calculate subtractive color

val_G = coeff_BG

val_R = (1.0-coeff_BG)*coeff_BR val_B = (1.0-coeff_BG)*(1.0-coeff_BR)

# find largest

val_max = max(val_R, val_G, val_B)

# scale so that largest is 1

val_G /= val_max val_R /= val_max val_B /= val_max

# scale to 255

color_G = int(255*val_G) color_R = int(255*val_R) color_B = int(255*val_B)

# set image value by subtracting from white

img_CMY_colors[n,m] -= np.array([color_R,color_G,color_B])

# flip the y axis

img_CMY_colors[:,:,:] = img_CMY_colors[-1::-1,:,:]

# display color image

plt.imshow(img_CMY_colors)

plt.title('CMY Subtractive Color System') plt.xticks([]), plt.yticks([])

plt.show()

def my_rgb2cmy(imgRGB):

height, width, ndim = imgRGB.shape

assert ndim == 3

# define RGB to CMY conversion table

rgb2cmy = np.array([[-1, 0, 0, 1],

[ 0, -1, 0, 1],

[ 0, 0, -1, 1]])

# create an image with 4 colors

imgRGB4 = np.zeros((height,width,4))

# first 3 colors are the original image data

imgRGB4[:,:,:3] = imgRGB

# 4th color is 255

imgRGB4[:,:,3] = 255

imgCMY = np.dot(imgRGB4, np.transpose(rgb2cmy)) imgCMY = imgCMY.astype('uint8')

return imgCMY

# 2.3 Conversion from RGB to CMY #set image folder

image_folder = r'/Users/tanjuerdem/EE421521/images'

# read input image

image_file = r'/rgb_color_wheel.png' image_path = image_folder + image_file imgRGB = io.imread(image_path)

# convert from RGB to CMY

imgCMY = my_rgb2cmy(imgRGB)

# back conversion function is the same as the conversion function!

imgRGB_fromCMY = my_rgb2cmy(imgCMY)

# display RGB and HSV images plt.figure(figsize=(15,5)) plt.subplot(131), plt.imshow(imgRGB) plt.title('Input RGB Image') plt.xticks([]), plt.yticks([]) plt.subplot(132), plt.imshow(imgCMY) plt.title('RGB Image Converted CMY') plt.xticks([]), plt.yticks([])

plt.subplot(133), plt.imshow(imgRGB_fromCMY) plt.title('CMY Image Converted Back to RGB') plt.xticks([]), plt.yticks([])

plt.show() plt.close()

In [70]:

In [71]:

Part 3: Conversion between RGB and HSV Color Spaces

# my function to convert from RGB to HSV

def my_RGB2HSV(imgRGB): N, M, D = imgRGB.shape assert N > 0

assert M > 0

assert D == 3

imgHSV = np.zeros((N,M,3), dtype=float) imgHue = np.zeros((N,M), dtype='uint8') imgSat = np.zeros((N,M), dtype='uint8') imgVal = np.zeros((N,M), dtype='uint8')

for n in range(N):

for m in range(M):

# get pixel color val = imgRGB[n,m] R = int(val[0])

G = int(val[1])

B = int(val[2])

# obtain Value

V = max(R,G,B)

# find minimum value

Min_val = min(R,G,B)

# find difference

Diff_val = V - Min_val

# obtain Saturation

if V == 0:

S = 0.0

else:

S = float(V-Min_val)/float(V)

# obtain Hue

if Diff_val == 0:

H = 0.0

else:

if V == R:

H = 60.0 + 60.0*float(G-B)/float(Diff_val)

elif V == G:

H = 180.0 + 60.0*float(B-R)/float(Diff_val)

else:

H = 300.0 + 60.0*float(R-G)/float(Diff_val)

# set HSV image value

imgHSV[n,m] = np.array([H,S,float(V)])

# hue image

In [72]:

imgHue[n,m] = int(round(H,0))

# saturation image

imgSat[n,m] = int(round(S*100,0))

# value image

imgVal[n,m] = V

return imgHSV, imgHue, imgSat, imgVal

# end of my function

# 3.1 Read an image and convert to HSV # set image folder

image_folder = r'/Users/tanjuerdem/EE421521/images'

# read input image

image_file = r'/peppers.png' image_path = image_folder + image_file imgRGB = io.imread(image_path)

# convert to HSV

imgHSV, imgHue, imgSat, imgVal = my_RGB2HSV(imgRGB)

# calculate the histogram of HSV bands

hist_H, bins = exposure.histogram(imgHue, source_range='dtype') hist_S, bins = exposure.histogram(imgSat, source_range='dtype') hist_V, bins = exposure.histogram(imgVal, source_range='dtype')

# original image and histrogram plot of Hue

plt.imshow(imgRGB) plt.title('Original RGB Image') plt.show()

# display HSV histogram data

plt.figure(figsize=(15,5))

plt.subplot(131), plt.plot(hist_H, color = 'b') plt.xlim([0,360])

plt.title('Histogram of Hue') plt.subplot(132), plt.plot(hist_S, color = 'b') plt.xlim([0,100])

plt.title('Histogram of Saturation') plt.subplot(133), plt.plot(hist_V, color = 'b') plt.xlim([0,256])

plt.title('Histogram of Value') plt.show()

plt.close()

# display HSV image

# auto-stretch to 0-255 range for display

plt.figure(figsize=(15,5))

plt.subplot(131), plt.imshow(imgHSV[:,:,0], cmap='gray') plt.title('Hue')

plt.subplot(132), plt.imshow(imgHSV[:,:,1], cmap='gray') plt.title('Saturation')

plt.subplot(133), plt.imshow(imgHSV[:,:,2], cmap='gray') plt.title('Value')

plt.show() plt.close()

In [73]:

In [74]:

# my function to convert from HSV to RGB

def my_HSV2RGB(imgHSV): N, M, D = imgHSV.shape assert N > 0

assert M > 0

assert D == 3

imgRGB = np.zeros((N,M,3), dtype='uint8')

for n in range(N):

for m in range(M):

# get pixel HSV value

val = imgHSV[n,m] H = val[0]

S = val[1] V = val[2]

if V != 0.0:

Min_val = V - S*V

else:

Min_val = 0.0

if H >= 0.0 and H < 120.0:

R = V

if H < 60.0:

G = Min_val

B = G - (H-60.0)*(V-Min_val)/60.0

else:

B = Min_val

G = B + (H-60.0)*(V-Min_val)/60.0

elif H >= 120.0 and H < 240.0:

G = V

if H < 180.0:

B = Min_val

R = B - (H-180.0)*(V-Min_val)/60.0

else:

R = Min_val

B = R + (H-180.0)*(V-Min_val)/60.0

else:

B = V

if H < 300.0:

R = Min_val

G = R - (H-300.0)*(V-Min_val)/60.0

else:

G = Min_val

R = G + (H-300.0)*(V-Min_val)/60.0

# integer values

R_int = min(max(int(round(R,0)),0),255) G_int = min(max(int(round(G,0)),0),255) B_int = min(max(int(round(B,0)),0),255)

# set RGB image value

imgRGB[n,m] = np.array([R_int,G_int,B_int])

return imgRGB

# end of my function

# 3.2 Convert HSV space back to RGB space

imgRGB_back = my_HSV2RGB(imgHSV)

# display orginal and HSV-then-RGB-back converted image

plt.figure(figsize=(10,5)) plt.subplot(121), plt.imshow(imgRGB) plt.title('Original Image') plt.subplot(122), plt.imshow(imgRGB_back) plt.title('HSV-then-RGB Converted Image') plt.show()

plt.close()

# 3.3 The Effect of Setting Saturation to 1

imgHSV_S1 = imgHSV.copy()

In [75]:

In [76]:

imgHSV_S1[:,:,1] = 1.0

imgRGB_S1 = my_HSV2RGB(imgHSV_S1)

# display orginal and HSV converted image plt.figure(figsize=(10,5)) plt.subplot(121), plt.imshow(imgRGB) plt.title('Original Image') plt.subplot(122), plt.imshow(imgRGB_S1) plt.title('HSV Saturation Set to 1') plt.show()

plt.close()

# 3.4 The Effect of Setting Value to 255

imgHSV_V255 = imgHSV.copy() imgHSV_V255[:,:,2] = 255.0

imgRGB_V255 = my_HSV2RGB(imgHSV_V255)

# display orginal and HSV converted image plt.figure(figsize=(10,5)) plt.subplot(121), plt.imshow(imgRGB) plt.title('Original Image') plt.subplot(122), plt.imshow(imgRGB_V255) plt.title('HSV Value Set to 255') plt.show()

plt.close()

# 3.5 The Effect of Setting Value to 255 & Saturation to 1

imgHSV_S1_V255 = imgHSV.copy() imgHSV_S1_V255[:,:,1] = 1.0

imgHSV_S1_V255[:,:,2] = 255.0

imgRGB_S1_V255 = my_HSV2RGB(imgHSV_S1_V255)

# compare all results

plt.figure(figsize=(10,10))

In [77]:

In [78]:

plt.subplot(221), plt.imshow(imgRGB) plt.title('Original Image') plt.subplot(222), plt.imshow(imgRGB_S1) plt.title('HSV Saturation Set to 1') plt.subplot(223), plt.imshow(imgRGB_V255) plt.title('HSV Value Set to 255') plt.subplot(224), plt.imshow(imgRGB_S1_V255)

plt.title('HSV Saturation Set to 1 & Value Set to 255') plt.show()

plt.close()

Part 4: Conversion between RGB and YUV Color Spaces

# my function to convert from RGB to YUV

def my_RGB2YUV(imgRGB): N, M, D = imgRGB.shape assert N > 0

assert M > 0

assert D == 3

# RGB to YUV conversion matrix

rgb2yuv = np.array([[0.299, 0.587, 0.114 ],

[-0.168736, -0.331264, 0.5 ],

[ 0.5, -0.418688, -0.081312]])

# convert from RGB to YUV

imgYUV = np.dot(imgRGB, np.transpose(rgb2yuv))

# add 128 to U and V bands

imgYUV[:,:,1] += 128.0

imgYUV[:,:,2] += 128.0

return imgYUV

# end of my function

In [79]:

In [80]:

# 4.1 Conversion from RGB to YUV

# set image folder

image_folder_new = r'/Users/tanjuerdem/EE421521/images'

# read input image

image_file_new = r'/peppers.png' #lena, fruits image_path_new = image_folder_new + image_file_new imgRGB_new = io.imread(image_path_new)

imgYUV = my_RGB2YUV(imgRGB_new)

# display original & YUV image

# auto-stretch to 0-255 range for display plt.figure(figsize=(10,10)) plt.subplot(221), plt.imshow(imgRGB_new) plt.title('Input RGB Image')

plt.subplot(222), plt.imshow(imgYUV[:,:,0], cmap='gray', vmin=0, vmax=255) plt.title('Luminance (Y)')

plt.subplot(223), plt.imshow(imgYUV[:,:,1], cmap='gray', vmin=0, vmax=255) plt.title('Chrominance-B (U)')

plt.subplot(224), plt.imshow(imgYUV[:,:,2], cmap='gray', vmin=0, vmax=255) plt.title('Chrominance-R (V)')

plt.show() plt.close()

In [81]:

# my function to convert from YUV to RGB

def my_YUV2RGB(imgYUV): N, M, D = imgYUV.shape assert N > 0

assert M > 0

assert D == 3

# YUV to RGB conversion matrix

yuv2rgb = np.array([[1.0, 0.0, 1.402 ],

[ 1.0, -0.344136, -0.714136],

[ 1.0, 1.772, 0.0 ]])

# subtract 128 from U and V bands imgYUV_new = imgYUV.copy() imgYUV_new[:,:,1] -= 128.0

imgYUV_new[:,:,2] -= 128.0

# convert from YUV to RGB

imgRGB = np.dot(imgYUV_new, np.transpose(yuv2rgb))

imgRGB = np.round(imgRGB, 0) imgRGB = np.minimum(imgRGB, 255) imgRGB = np.maximum(imgRGB, 0) imgRGB = imgRGB.astype('uint8')

return imgRGB

# end of my function

# 4.2 Conversion from YUV back to RGB

imgRGB_fromYUV = my_YUV2RGB(imgYUV)

# display RGB image converted back from YUV plt.figure(figsize=(10,5)) plt.subplot(121), plt.imshow(imgRGB_new) plt.title('Original Image')

plt.subplot(122), plt.imshow(imgRGB_fromYUV) plt.title('RGB Image Converted Back from YUV') plt.show()

plt.close()

# display RGB & YUV color bands together

x_R = imgRGB_new[:,:,0] x_G = imgRGB_new[:,:,1] x_B = imgRGB_new[:,:,2]

x_Y = imgYUV[:,:,0]

x_U = imgYUV[:,:,1]

x_V = imgYUV[:,:,2]

# apply no stretching

plt.figure(figsize=(15,10))

plt.subplot(231), plt.imshow(x_R, cmap='gray', vmin=0, vmax=255) plt.xticks([]), plt.yticks([]), plt.title('R') plt.subplot(232), plt.imshow(x_G, cmap='gray', vmin=0, vmax=255) plt.xticks([]), plt.yticks([]), plt.title('G') plt.subplot(233), plt.imshow(x_B, cmap='gray', vmin=0, vmax=255) plt.xticks([]), plt.yticks([]), plt.title('B') plt.subplot(234), plt.imshow(x_Y, cmap='gray', vmin=0, vmax=255) plt.xticks([]), plt.yticks([]), plt.title('Luminance (Y)') plt.subplot(235), plt.imshow(x_U, cmap='gray', vmin=0, vmax=255) plt.xticks([]), plt.yticks([]), plt.title('Chrominance-B (U)') plt.subplot(236), plt.imshow(x_V, cmap='gray', vmin=0, vmax=255) plt.xticks([]), plt.yticks([]), plt.title('Chrominance-R (V)') plt.show()

plt.close()

In [82]:

In [83]:

Part 5: Fourier Analysis of YUV Bands

# my function to multiply an image with (-1)^(i+j)

# so that the origin of its DFT is displayed at the center

def my_img_shift(img): height, width = img.shape

assert height%2 == 0 and width%2 == 0 img_shift = img.copy() + 0.0

for i in range(height):

for j in range(width):

if (i+j)%2 == 1: img_shift[i,j] *= -1.0

return img_shift

# end of function

# my function to obtain a display-friendly version of 2-D DFT of an image

# (used for displaying DFT magnitude, DFT real part, and DFT imaginary part)

def my_log_display(X_orig): X = X_orig.copy() shapeX = X.shape

X = X.reshape(-1)

for i in range(X.size):

if X[i] < 0:

# this is needed for real and imaginary parts

X[i] = - np.log(1-X[i])

else:

# magnitude is always non-negative

X[i] = np.log(1+X[i])

return X.reshape(shapeX)

In [84]:

In [85]:

# end of function

# 5.1 Calculate and plot the DFT of the YUV bands

height, width, dim = imgYUV.shape

# multiply the image with (-1)^(i+j) before DFT so that DFT origin is displayed at the center

x_Y_shift = my_img_shift(x_Y) x_U_shift = my_img_shift(x_U) x_V_shift = my_img_shift(x_V)

# calculate the 2-D DFT via SciPy's 2-D DFT function

X_Y_shift = ft.fft2(x_Y_shift) X_U_shift = ft.fft2(x_U_shift) X_V_shift = ft.fft2(x_V_shift)

# DFT magnitude

X_Y_mag = np.abs(X_Y_shift) X_U_mag = np.abs(X_U_shift) X_V_mag = np.abs(X_V_shift)

# get a display friendly version for magnitude X_Y_mag_pr = my_log_display(X_Y_mag) X_U_mag_pr = my_log_display(X_U_mag) X_V_mag_pr = my_log_display(X_V_mag)

# extract the center line X_Y_center = X_Y_mag_pr[height//2,:] X_U_center = X_U_mag_pr[height//2,:] X_V_center = X_V_mag_pr[height//2,:]

# smooth the center line

smt_size = 5

smt_filter = np.ones((smt_size,)) smt_filter /= smt_filter.sum()

X_Y_center_smooth = signal.convolve(X_Y_center, smt_filter, 'same') X_U_center_smooth = signal.convolve(X_U_center, smt_filter, 'same') X_V_center_smooth = signal.convolve(X_V_center, smt_filter, 'same')

plt.figure(figsize=(15,10))

plt.subplot(231), plt.imshow(X_Y_mag_pr, cmap='gray', vmin=8, vmax=15) plt.title('DFT Magnitude Y')

plt.subplot(232), plt.imshow(X_U_mag_pr, cmap='gray', vmin=8, vmax=15) plt.title('DFT Magnitude U')

plt.subplot(233), plt.imshow(X_V_mag_pr, cmap='gray', vmin=8, vmax=15) plt.title('DFT Magnitude V')

plt.subplot(234), plt.ylim((8, 15)), plt.plot(X_Y_center_smooth) plt.title('Horizontal Cross Section Y')

plt.subplot(235), plt.ylim((8, 15)), plt.plot(X_U_center_smooth) plt.title('Horizontal Cross Section U')

plt.subplot(236), plt.ylim((8, 15)), plt.plot(X_V_center_smooth) plt.title('Horizontal Cross Section V')

plt.show() plt.close()

In [86]:

In [87]:

# 5.2 Calculate and plot the DFT of the RGB bands

height, width, dim = imgRGB_new.shape

# multiply the image with (-1)^(i+j) before DFT so that DFT origin is displayed at the center

x_R_shift = my_img_shift(x_R) x_G_shift = my_img_shift(x_G) x_B_shift = my_img_shift(x_B)

# calculate the 2-D DFT via SciPy's 2-D DFT function

X_R_shift = ft.fft2(x_R_shift) X_G_shift = ft.fft2(x_G_shift) X_B_shift = ft.fft2(x_B_shift)

# DFT magnitude

X_R_mag = np.abs(X_R_shift) X_G_mag = np.abs(X_G_shift) X_B_mag = np.abs(X_B_shift)

# get a display friendly version for magnitude X_R_mag_pr = my_log_display(X_R_mag) X_G_mag_pr = my_log_display(X_G_mag) X_B_mag_pr = my_log_display(X_B_mag)

# extract the center line X_R_center = X_R_mag_pr[height//2,:] X_G_center = X_G_mag_pr[height//2,:] X_B_center = X_B_mag_pr[height//2,:]

# smooth the center line

smt_size = 5

smt_filter = np.ones((smt_size,)) smt_filter /= smt_filter.sum()

X_R_center_smooth = signal.convolve(X_R_center, smt_filter, 'same') X_G_center_smooth = signal.convolve(X_G_center, smt_filter, 'same') X_B_center_smooth = signal.convolve(X_B_center, smt_filter, 'same')

plt.figure(figsize=(15,10))

plt.subplot(231), plt.imshow(X_R_mag_pr, cmap='gray', vmin=8, vmax=15) plt.title('DFT Magnitude R')

plt.subplot(232), plt.imshow(X_G_mag_pr, cmap='gray', vmin=8, vmax=15)

plt.title('DFT Magnitude G')

plt.subplot(233), plt.imshow(X_B_mag_pr, cmap='gray', vmin=8, vmax=15) plt.title('DFT Magnitude B')

plt.subplot(234), plt.ylim((8, 15)), plt.plot(X_R_center_smooth) plt.title('Horizontal Cross Section R')

plt.subplot(235), plt.ylim((8, 15)), plt.plot(X_G_center_smooth) plt.title('Horizontal Cross Section G')

plt.subplot(236), plt.ylim((8, 15)), plt.plot(X_B_center_smooth) plt.title('Horizontal Cross Section B')

plt.show() plt.close()

# calculate the standard deviation of pixel values in an image band

def my_std(img):

# single band image only

assert img.ndim == 2

# calculate the average value

ave_val = img.sum()/float(img.size)

# calculate and return the standard deviation

return math.sqrt(((img-ave_val)**2).sum() / img.size)

# end of function

# 5.5 Compare the Fourier bandwidths and standard deviations of RGB and YUV bands

plt.figure(figsize=(15,10))

plt.subplot(231), plt.imshow(X_R_mag_pr, cmap='gray', vmin=8, vmax=15) plt.title('DFT Magnitude R (std = {:.2f})'.format(my_std(x_R))) plt.subplot(232), plt.imshow(X_G_mag_pr, cmap='gray', vmin=8, vmax=15) plt.title('DFT Magnitude G (std = {:.2f})'.format(my_std(x_G))) plt.subplot(233), plt.imshow(X_B_mag_pr, cmap='gray', vmin=8, vmax=15) plt.title('DFT Magnitude B (std = {:.2f})'.format(my_std(x_B))) plt.subplot(234), plt.imshow(X_Y_mag_pr, cmap='gray', vmin=8, vmax=15) plt.title('DFT Magnitude Y (std = {:.2f})'.format(my_std(x_Y))) plt.subplot(235), plt.imshow(X_U_mag_pr, cmap='gray', vmin=8, vmax=15) plt.title('DFT Magnitude U (std = {:.2f})'.format(my_std(x_U)))

In [88]:

In [89]:

plt.subplot(236), plt.imshow(X_V_mag_pr, cmap='gray', vmin=8, vmax=15) plt.title('DFT Magnitude V (std = {:.2f})'.format(my_std(x_V))) plt.show()

plt.close()

In [ ]: