I am trying to adapt the code here : http://code.activestate.com/recipes/577166-newton-fractals/ into C and am having some trouble. I am using C99's complex type.
I basically have tried a few different approaches which haven't worked. On every pixel it goes all the way to the maximum iteration every time, so the image comes out as a solid color.
Is there soemthing I have fundementally wrong about the way the types work in C, it seems like it should work, I reconstructed the algorithm pretty exactly.
//newt.c
#include <stdio.h>
#include <stdlib.h>
#include <complex.h>
#include <float.h>
#include <math.h>
complex f(complex z);
const int WIDTH = 512, HEIGHT = 512;
const double SCALED_X_MAX = 1.0;
const double SCALED_X_MIN = -1.0;
const double SCALED_Y_MAX = 1.0;
const double SCALED_Y_MIN = -1.0;
const int MAX_ITERATIONS = 20;
const int EPSILON = 1e-3;
int main(int argc, char **argv) {
const double SCALED_WIDTH = SCALED_X_MAX - SCALED_X_MIN ;
const double SCALED_HEIGHT = SCALED_Y_MAX - SCALED_Y_MIN ;
FILE * image = fopen("newton.ppm", "w") ;
fprintf(image, "P3\n");
fprintf(image, "%d %d\n" , WIDTH , HEIGHT ) ;
fprintf(image, "%d\n", 255) ;
for ( int y = 0 ; y < HEIGHT ; ++y) {
double zy = y * (SCALED_HEIGHT)/(HEIGHT-1) + SCALED_Y_MIN;
for ( int x = 0 ; x < WIDTH ; ++x ) {
double zx = x * (SCALED_WIDTH)/(WIDTH-1) + SCALED_X_MIN;
complex z = zx + zy*I;
int iteration = 0;
while(iteration < MAX_ITERATIONS ) {
// complex h=sqrt(DBL_EPSILON) + sqrt(DBL_EPSILON)*I;
double h=1e-6;
/*
complex zph = z + h;
complex dz = zph - z;
complex slope = (f(zph) - f(z))/dz;
*/
complex volatile dz = (f(z + (h+h*I)) - f(z)) / (h+I*h) ;
complex z0 = z - f(z) / dz;
//fprintf(stdout,"%f \n", cabs(z0 - z ));
if ( cabs(z0 - z) < EPSILON){
break;
}
z = z0;
iteration++;
}
if (iteration != MAX_ITERATIONS) fprintf(stdout, "%d " , iteration );
fprintf(image,"%3d %3d %3d ", iteration % 4 * 64 ,
iteration % 8 * 32 ,
iteration % 16 * 16);
}
fprintf(image, "\n") ;
}
fclose(image) ;
exit(0);
}
complex f(complex z ) {
return cpow(z,3)-1.0 ;
}
After checking over the complex maths and not seeing any problems I noticed that your error is simply due to the integer division in the line
zy = y * (SCALED_HEIGHT)/(HEIGHT-1) + SCALED_Y_MIN;
and similarly for zx. Because (SCALED_HEIGHT) and (HEIGHT-1) are both integers this is not going to give you the floating point result you require. Try using:
zy = y * SCALED_HEIGHT * 1.0/(HEIGHT-1) + SCALED_Y_MIN;
and similarly for zx.
EDIT: Sorry the above was in error. Your SCALED_HEIGHT was in fact double so the above was actually ok. The real problem is simply in the line
const int EPSILON = 1e-3;
This will in fact always return zero, because it's an integer. You need to make EPSILON a floating point type.
Related
What is a correct way to do the matrix multiplication using ctype ?
in my current implementation data going back and forth consuming lots of time, is there any way to do it optimally ? by passing array address and getting pointer in return instead of generating entire array using .contents method.
cpp_function.cpp
compile using g++ -shared -fPIC cpp_function.cpp -o cpp_function.so
#include <iostream>
extern "C" {
double* mult_matrix(double *a1, double *a2, size_t a1_h, size_t a1_w,
size_t a2_h, size_t a2_w, int size)
{
double* ret_arr = new double[size];
for(size_t i = 0; i < a1_h; i++){
for (size_t j = 0; j < a2_w; j++) {
double val = 0;
for (size_t k = 0; k < a2_h; k++){
val += a1[i * a1_h + k] * a2[k * a2_h +j] ;
}
ret_arr[i * a1_h +j ] = val;
// printf("%f ", ret_arr[i * a1_h +j ]);
}
// printf("\n");
}
return ret_arr;
}
}
Python file to call the so file
main.py
import ctypes
import numpy
from time import time
libmatmult = ctypes.CDLL("./cpp_function.so")
ND_POINTER_1 = numpy.ctypeslib.ndpointer(dtype=numpy.float64,
ndim=2,
flags="C")
ND_POINTER_2 = numpy.ctypeslib.ndpointer(dtype=numpy.float64,
ndim=2,
flags="C")
libmatmult.mult_matrix.argtypes = [ND_POINTER_1, ND_POINTER_2, ctypes.c_size_t, ctypes.c_size_t]
def mult_matrix_cpp(a,b):
shape = a.shape[0] * a.shape[1]
libmatmult.mult_matrix.restype = ctypes.POINTER(ctypes.c_double * shape )
ret_cpp = libmatmult.mult_matrix(a, b, *a.shape, *b.shape , a.shape[0] * a.shape[1])
out_list_c = [i for i in ret_cpp.contents] # <---- regenrating list which is time consuming
return out_list_c
size_a = (300,300)
size_b = size_a
a = numpy.random.uniform(low=1, high=255, size=size_a)
b = numpy.random.uniform(low=1, high=255, size=size_b)
t2 = time()
out_cpp = mult_matrix_cpp(a,b)
print("cpp time taken:{:.2f} ms".format((time() - t2) * 1000))
out_cpp = numpy.array(out_cpp).reshape(size_a[0], size_a[1])
t3 = time()
out_np = numpy.dot(a,b)
# print(out_np)
print("Numpy dot() time taken:{:.2f} ms".format((time() - t3) * 1000))
This solution works but time consuming is there any way to make it faster ?
One reason for the time consumption is not using an ndpointer for the return value and copying it into a Python list. Instead use the following restype. You won't need the later reshape as well. But take the commenters' advice and don't reinvent the wheel.
def mult_matrix_cpp(a, b):
shape = a.shape[0] * a.shape[1]
libmatmult.mult_matrix.restype = np.ctypeslib.ndpointer(dtype=np.float64, ndim=2, shape=a.shape, flags="C")
return libmatmult.mult_matrix(a, b, *a.shape, *b.shape , a.shape[0] * a.shape[1])
use restype
def mult_matrix_cpp(a, b):
shape = a.shape[0] * a.shape[1]
libmatmult.mult_matrix.restype = np.ctypeslib.ndpointer(dtype=np.float64, ndim=2, shape=a.shape, flags="C")
return libmatmult.mult_matrix(a, b, *a.shape, *b.shape , a.shape[0] * a.shape[1])
so Im trying to implement the hough transform using python and c++ (using Pybind11 for interfacing between the two languages). When Im plotting the hough space it seems alright but I just can't get a line from the maximum of the voting matrix.
Here is the C++ code (looks a bit different bc I use PyBind11):
py::array_t<int> houghTransform(py::array_t<int> image, int angleStep, int angleAmount) {
auto imageBuf = image.mutable_unchecked<3>();
int height = imageBuf.shape(0);
int width = imageBuf.shape(1);
py::array_t<int> edgeMatrix = edgeDetect(imageBuf, height, width);
auto edgeMatrixBuf = edgeMatrix.mutable_unchecked<2>();
int distanceAxis = 2 * sqrt(pow((float) height, 2.0) + pow((float) width, 2.0));
int angleAxis = angleAmount;
int angleDim = (int) angleAxis / angleStep;
int distanceDim = (int) distanceAxis / 2;
py::array_t<int> votingMatrix = py::array_t<int>({distanceAxis, angleDim});
auto votingMatrixBuf = votingMatrix.mutable_unchecked<2>();
// fill voting matrices with zeros
for(int i=0; i<distanceDim; i++) {
for(int j=0; j<angleDim; j++) {
votingMatrixBuf(i, j) = 0;
}
}
// vote
for(int x=0; x<edgeMatrixBuf.shape(0); x++) {
for(int y=0; y<edgeMatrixBuf.shape(1); y++) {
if(edgeMatrixBuf(x, y) == 1) {
int counter = 0;
float theta;
float ro;
for(int thetaIdx=0; thetaIdx<=angleAxis; thetaIdx++) {
if(thetaIdx % angleStep == 0) {
counter++;
theta = (float) (thetaIdx) * (M_PI / 180);
ro = distanceDim + std::round((x * cos(theta)) + (y * sin(theta)));
votingMatrixBuf(ro, counter) += 1;
}
}
}
}
}
return votingMatrix;
}
As you can see the arguments of the functions are the image matrix, which I transform to a matrix where the edges are 1 and the rest 0, so I got my pixels of interest.
int angleAmount is what angle range I want to try outand int angleStep is how many of angles of that theta I really want to use (for example, skip every second theta). But for this example I will use angleAmount = 360 and angleStep = 1. So I will use all angles form 1 to 360.
Here is the python code:
from PIL import Image
import numpy as np
import matplotlib.pyplot as plt
import time
from houghTransform import houghTransform
def apply_hough_transform(image_path: str=""):
image = np.array(Image.open(image_path))
lines = houghTransform(image, 1, 360)
p = np.unravel_index(lines.argmax(), lines.shape)
max_distance = 2 * np.sqrt(pow(image.shape[0], 2) + pow(image.shape[1], 2))
ro = p[0] - (max_distance / 2)
theta = p[1] * (np.pi / 180)
a = np.cos(theta)
b = np.sin(theta)
x = a * ro
y = b * ro
pt1 = (int(x + 1000*(-b)), int(y + 1000*(a)))
pt2 = (int(x - 1000*(-b)), int(y - 1000*(a)))
fig, axs = plt.subplots(2)
axs[0].matshow(lines)
axs[0].scatter(p[1], p[0], facecolors="none", edgecolors="r")
axs[1].plot([pt1[0], pt2[0]], [pt1[1], pt2[1]])
axs[1].imshow(image)
plt.show()
apply_hough_transform(image_path="images/black_line.png")
The function houghTransform is the same as in the c++ code which I exported to Python using PyBind11.
Here are the images:
I also tried to create the line using this function:
def line(x):
return -(1 / np.arctan(theta)) * (x - ro * np.cos(theta)) + ro * np.sin(theta)
But it also didnt work.
Can you spot my error? Im sitting on this for quite some time so help is really appreciated!
I have an image and I would like to keep the centre opaque and slowly increase the transparency of the image going towards the edges. I'm trying to do this in Python with cv2 but am not having any luck. Initial I though of creating a gaussian function in the alpha channel. Does anyone know a good way to do this?
This is a C++ solution that assumes you have an RGBA image (UINT8 or UINT16)
void addTransparency(cv::Mat &mat)
{
int s = min(mat.rows, mat.cols) / 2;
for (int i = 0; i < mat.rows; ++i) {
for (int j = 0; j < mat.cols; ++j) {
cv::Vec4b& rgba = mat.at<cv::Vec4b>(i, j);
float r = sqrt( (float) (i - mat.rows/2)*(i - mat.rows/2) + (j - mat.cols/2)*(j - mat.cols/2) );
rgba[3] = saturate_cast<uchar>( 255 * exp( - (r * r) / (2 * s * s) ) );
}
}
}
You can read more here
I'm attempting to implement the discrete time wave equation in OpenCL. I think I'm pretty close, but the results look like what I would expect from the heat equation. I know they're very similar, but when I've implemented the 2D wave equation (not using OpenCL) I got distinct wavefronts and reflections. With the OpenCL kernel below everything diffuses until it is a wash.
__kernel void wave_calc(
__global float* height,
__global float* height_old,
const unsigned int len_x,
const unsigned int len_y,
const unsigned int len_z,
const float dtxc_term)
{
unsigned int x = get_global_id(0);
unsigned int y = get_global_id(1);
unsigned int z = get_global_id(2);
int this_cell = x + len_y * (y + len_x * z);
float laplacian;
if (x==0 || x==(len_x-1) || y==0 || y==(len_y-1) || z==0 || z==(len_z-1)) {
laplacian = 0;
height_old[this_cell] = height[this_cell];
height[this_cell] = 0;
}
else if ( x < len_x-1 && y < len_y-1 && z < len_z-1 ){
int n1 = x - 1 + len_y * (y + len_x * z);
int n2 = x + 1 + len_y * (y + len_x * z);
int n3 = x + len_y * (y - 1 + len_x * z);
int n4 = x + len_y * (y + 1 + len_x * z);
int n5 = x + len_y * (y + len_x * (z -1));
int n6 = x + len_y * (y + len_x * (z + 1));
laplacian = -6 * height[this_cell] +
height[n1] +
height[n2] +
height[n3] +
height[n4] +
height[n5] +
height[n6];
height_old[this_cell] = height[this_cell];
height[this_cell] = (dtxc_term*laplacian+2*height[this_cell]) - height_old[this_cell];
}
}
(DTXC is the result of ((DT * DT)/(DX * DX)) * C passed from the host)
Every step I copy height back to the host for plotting, and then call the function again.
for i in np.arange(steps):
#copy height from host to device
cl.enqueue_copy(queue, d_height, h_height)
#step once
wave_calc(queue, field_3d.shape, None, d_height, d_height_old, LEN_X, LEN_Y, LEN_Z, DTXC)
queue.finish()
#copy height back
cl.enqueue_copy(queue, h_height, d_height)
#do my plotting
Any thoughts/suggestions/condescending remarks? All would be appreciated. :)
Here is an update to answer Joel's question:
I'm not much good when it comes to calculus, but I'm taking a working C++ implementation in 2D and trying to adapt it for 3D. Below is the C++. The only modification I made was to the loop, since there are 6 neighbor cells in 3D instead of 4. In both cases the outer walls of the plane/cube are set to 0:
for(int x=1; x<field.xRes()-1;x++) {
for (int y=1; y<field.yRes()-1; y++) {
laplacian(x,y) = -4 * height(x,y) +
height(x-1,y) +
height(x+1,y) +
height(x,y-1) +
height(x,y+1);
}
}
const float dt = 0.001;
const float xLen = 1.0;
const float C = 1.0;
const float dx = xLen/xRes;
backup = height;
height = ((dt*dt)/(dx*dx))*C*laplacian+2*height;
height = height - heightOld;
heightOld = backup;
I am trying to wrap some C code with Cython, but I am running into a error that I don't understand, and despite a lot of searching I cannot seem to find anything on it. Here is my c code
void cssor(double *U, int m, int n, double omega, double tol, int maxiters, int *info){
double maxerr, temp, lcf, rcf;
int i, j, k;
lcf = 1.0 - omega;
rcf = 0.25 * omega;
for (k =0; k < maxiters ; k ++){
maxerr = 0.0;
for (j =1; j < n-1; j++) {
for (i =1; i < m-1; i++) {
temp = U[i*n+ j];
U[i*n+j] = lcf * U[i*n+j] + rcf * (U[i*n+j-1] + U [i*n+j+1] + U [(i-1)*n + j] + U [(i+1)*n+j]);
maxerr = fmax(fabs(U[i*n+j] - temp), maxerr);
}
}
if(maxerr < tol){break;}
}
if (maxerr < tol) {*info =0;}
else{*info =1;}
}
My .pyx file is
cdef extern from "cssor.h":
void cssor(double *U, int m, int n, double omega, double tol, int maxiters, int *info)
cpdef cyssor(double[:, ::1] U, double omega, double tol, int maxiters, int *info):
cdef int n, m
m = U.shape[0]
n = U.shape[1]
cssor(&U[0, 0], m, n, omega, tol, maxiters, &info)
However, when I try to run the associated setup file I get an error referring to maxiters in the last line of the code that says:
Cannot assign type 'int **' to type 'int *'
Can you tell me how to fix this?
Roy Roth
The problem comes from here:
cpdef cyssor(double[:, ::1] U, double omega, double tol, int maxiters, int *info):
cdef int n, m
m = U.shape[0]
n = U.shape[1]
cssor(&U[0, 0], m, n, omega, tol, maxiters, &info)
You declare info as type int*. But you then pass it into the cssor function as a reference to an int*, making it an int**.
The correct code is:
cssor(&U[0, 0], m, n, omega, tol, maxiters, info)