I'm trying to rewrite Zhao Koch steganography method from matlab into python and I am stuck right at the start.
The first two procedures as they are in matlab:
Step 1:
A = imread(casepath); # Reading stegonography case image and aquiring it's RGB values. In my case it's a 400x400 PNG image, so it gives a 400x400x3 array.
Step 2:
D = dct2(A(:,:,3)); # Applying 2D DCT to blue values of the image
Python code analog:
from scipy import misc
from numpy import empty,arange,exp,real,imag,pi
from numpy.fft import rfft,irfft
arr = misc.imread('casepath')# 400x480x3 array (Step 1)
arr[20, 30, 2] # Getting blue pixel value
def dct(y): #Basic DCT build from numpy
N = len(y)
y2 = empty(2*N,float)
y2[:N] = y[:]
y2[N:] = y[::-1]
c = rfft(y2)
phi = exp(-1j*pi*arange(N)/(2*N))
return real(phi*c[:N])
def dct2(y): #2D DCT bulid from numpy and using prvious DCT function
M = y.shape[0]
N = y.shape[1]
a = empty([M,N],float)
b = empty([M,N],float)
for i in range(M):
a[i,:] = dct(y[i,:])
for j in range(N):
b[:,j] = dct(a[:,j])
return b
D = dct2(arr) # step 2 anlogue
However, when I try to execute the code I get the following error:
Traceback (most recent call last):
File "path to .py file", line 31, in <module>
D = dct2(arr)
File "path to .py file", line 25, in dct2
a[i,:] = dct(y[i,:])
File "path to .py file", line 10, in dct
y2[:N] = y[:]
ValueError: could not broadcast input array from shape (400,3) into shape (400)
Perhaps someone could kindly explain to me what am I doing wrong?
Additional Info:
OS: Windows 10 Pro 64 bit
Python: 2.7.12
scipy:0.18.1
numpy:1.11.2
pillow: 3.4.1
Your code works fine, but it is designed to only accept a 2D array, just like dct2() in Matlab. Since your arr is a 3D array, you want to do
D = dct2(arr[...,2])
As mentioned in my comment, instead or reinventing the wheel, use the (fast) built-in dct() from the scipy package.
The code from the link in my comment effectively provides you this:
import numpy as np
from scipy.fftpack import dct, idct
def dct2(block):
return dct(dct(block.T, norm='ortho').T, norm='ortho')
def idct2(block):
return idct(idct(block.T, norm='ortho').T, norm='ortho')
But again, I must stress that you have to call this function for each colour plane individually. Scipy's dct() will happily accept any N-dimensional array and will apply the transform on the last axis. Since that's your colour planes and not your rows and columns of your pixels, you'll get the wrong result. Yes, there is a way to address this with the axis input parameter, but I won't unnecessarily overcomplicate this answer.
Regarding the various DCT implementations involved here, your version and scipy's implementation give the same result if you omit the norm='ortho' parameter from the snippet above. But with that parameter included, scipy's transform will agree with Matlab's.
Related
I am working on a project that involves both Matlab and Python and I am producing some images. Altough the matrixes I want to transform into images are the same, the images I get are not the same. I assume this has something to do with the equivalence between Python and Matlab commands for displaying images and thus this is why I am here.
MATLAB CODE:
fmn0 = imread('cameraman.tif');
fmn=double(ifftshift(fmn0,2));
Fun=fftshift(fft(fmn,[],2),2);
imshow(real(Fun))
MATLAB OUTPUT:
PYTHON CODE:
import numpy as np
import matplotlib.pyplot as plt
import cv2
def row_wise_fft(A):
A = np.asarray(A)
rowWiseFFT = np.zeros((A.shape[0], A.shape[1]), dtype='complex')
for i in range(0, A.shape[0]):
rowWiseFFT[i, :] = np.fft.fft(A[i,:])
return rowWiseFFT
def row_wise_ifftshift(A):
for i in range(0, len(A)):
A[i] = np.fft.ifftshift(A[i])
return A
def row_wise_fftshift(A):
for i in range(0, len(A)):
A[i] = np.fft.fftshift(A[i])
return A
fmn = cv2.imread("cameraman.tif", cv2.IMREAD_GRAYSCALE)
fun = row_wise_fftshift(row_wise_fft(row_wise_ifftshift(fmn)))
plt.set_cmap("Greys_r")
plt.imshow(fun.real)
PYHTON OUTPUT:
I can see some similarities, but how would one leave the Python output as the exact same as the Matlab one? Note that the fun matrixes are the exact same.
MATLAB autoscales the output to [0 1], so most of your data in the MATLAB plot is extremely saturated and not really visible.
do imshow(real(Fun),[]) to remove the saturation and actually see all your data (MATLAB).
do plt.clim([0,1]) to saturate the visualization of your data in python.
You can also just give either MATLAB or python a different range of values to visualize (e.g. [0, 15])
I was wondering if anyone would know how to translate a function I have from Matlab to Python and C++. The main problem I have is to find an interpolation function equivalent to Matlab's scatteredInterpolant. I have searched for more information and found this other entry but I have not been able to adapt the code, so I was wondering if anyone would know.
The simplified Matlab function would be as follows
function data_out = test_interp (data_input)
U = rand(20,20);
V = rand(20,20);
[X,Y] = meshgrid(1:20,1:20);
% Create matrix with specific format.
aux_array = [reshape(U,[],1) reshape(V,[],1) reshape(X,[],1) reshape(Y,[],1)];
% Apply scatteredInterpolant with vector arrays.
FX = scatteredInterpolant(aux_array(:,1),aux_array(:,2), aux_array(:,3));
FY = scatteredInterpolant(aux_array(:,1),aux_array(:,2), aux_array(:,4));
% Apply FX and FY to the desired input.
data_out(:,1) = FX(data_input(:,1),data_input(:,2));
data_out(:,2) = FY(data_input(:,1),data_input(:,2));
end
What it would do would be to perform the interpolation between two matrices and apply them to some input data, a way to call the function would be: data_out = test_interp (rand(10,2))
I note the fact that the matrices are actually much larger and are not randomly generated, but they are useful to understand the effect.
I was testing and in Python what I managed to do is the following:
import numpy as np
from scipy.interpolate import griddata
def test_interp (data_input):
# Generate
U = np.random.random([20, 20])
V = np.random.random([20, 20])
[X, Y] = np.meshgrid(np.linspace(1, 20, 20), np.linspace(1, 20, 20))
xx = griddata((X.flatten(), Y.flatten()),U.flatten(),(data_input[:,0],data_input[:,1]),method='linear')
yy = griddata((X.flatten(), Y.flatten()),V.flatten(),(data_input[:,0],data_input[:,1]),method='linear')
data_mm = [xx, yy]
return data_mm
But from what I was seeing the griddata function is not well implemented, I also tried with np.interp2d but I didn't get the same thing.
With C++ the same thing happens to me, I wouldn't know which function I should use to replace the Matlab function.
I am using python opencv version 4.5.
import cv2
import numpy as np
rigidRect = np.float32([[50,-50],[50,50],[-50,50]])
shiftRect = np.float32([[50,-30],[50,70],[-50,70]])
M = cv2.getAffineTransform(rigidRect, shiftRect) #this return [[1,0,0],[0,1,20]]
validateRect = cv2.warpAffine(rigidRect, M, (2,3))
and validateRect return a 3 by 2 zeroes matrix.
I thought validateRect will equal to shiftRect?
warpAffine is used to transform an image using the affine transform matrix. What you are trying to do is to transform the given points, which is achieved by the transform function. Documentation of getAffineTransform gives hint about related functions in see also part.
validateRect = cv2.transform(rigidRect[None,:,:], M)
I made a 3D array, which consists of numbers(0~4). What I want is to save 3D array as a stack of 2D images(if possible, save *.tiff file). What am I supposed to do?
import numpy as np
a = np.random.randint(0,5, size=(100,100,100))
a = a.astype('int8')
Actually, I made it. This is my code.
With this code, I don't need to stack a series of 2D image(array).
Make a 3D array, and save it. That is just what I did for this.
import numpy as np
from skimage.external import tifffile as tif
a = np.random.randint(0,5, size=(100,100,100))
a = a.astype('int8')
tif.imsave('a.tif', a, bigtiff=True)
This should work. I haven't tested it but I have separated color images into RGB slices using this method and it should work pretty much the same way here, assuming you don't want to do anything with those pixel values first. (They will be very close to the same color in an image).
import imageio
import numpy as np
a = np.random.randint(0,5, size=(100,100,100))
a = a.astype('int8')
for i in range(100):
newimage = a[:, :, i]
imageio.imwrite("path/to/image%d.tiff" %i, newimage)
What exactly do you mean by "stack"? As you refer to tiff as output format, I assume here you want your data in one file as a multiframe-tiff.
This can easily be done with imageio's mimwrite() function:
# import numpy as np
# a = np.random.randint(0,5, size=(100,100,100))
# a = a.astype('int8')
import imageio
imageio.mimwrite("image.tiff", a)
Note that this function relies on having the counter for your several frames as first parameter and x and y follw. See also its documentation.
However, if I'm wrong and you want to have n (e.g. 100) separate tif-files, you can also use the normal imwrite() function in a loop:
n = len(a)
for i in range(n):
imageio.imwrite(f'image_{i:03}.tiff', a[i])
i've recreated a code of Haar Tranform matrix from matlab to python it's a success upon entering the value of n for 2 and 4 but when i'm trying to input 8 there's an error
"Traceback (most recent call last):
File "python", line 20, in
ValueError: shape too large to be a matrix."
here's my code
import numpy as np
import math
n=8
# check input parameter and make sure it's the power of 2
Level1 = math.log(n, 2)
Level = int(Level1)+1
#Initialization
H = [1]
NC = 1 / math.sqrt(2) #normalization constant
LP = [1, 1]
HP = [1,-1]
for i in range(1,Level):
H = np.dot(NC, [np.matrix(np.kron(H, LP)), np.matrix(np.kron(np.eye(len(H)), HP))])
print H
I'm assuming you got the definition of the haar transform from the wikipedia article or a similar source, so I'll try to stick to their notation.
The problem with your code is that on the wikipedia article a slight abuse of notation is used. In the equation defining H_2N in terms of H_N, two matrices are stacked on top of eachother with brackets around them. Technically, this would be something like an array consisting of 2 arrays, but they mean it to be a single array where the top half of the values is equal to the one matrix and the bottom half equal to the other matrix.
In your code, the array of two matrices is the following part:
[np.matrix(np.kron(H, LP)), np.matrix(np.kron(np.eye(len(H)), HP))]
You can make this into a single matrix as described above using the np.concatenate function as follows:
H = np.dot(NC, np.concatenate([np.matrix(np.kron(H, LP)), np.matrix(np.kron(np.eye(len(H)), HP))]))