To preface this: I'm currently a first-year student who was allowed to enroll in some second-year classes. Because of this, I'm currently wrangling a language (C++) that I haven't really had the time to learn (First-years mostly learn C#), so this code might not be pretty.
Our assignment is twofold. First, we need to write a program that outputs a Mandelbrot image in a PPM. To achieve this, I've followed a Youtube tutorial here.
The second part of the assignment is to make the program multithreaded. Essentially, the program is supposed to use 4 threads that each draw a quarter of the image.
To this end I have altered the code from the video tutorial, and converted the main to a method. Now, I'm trying to properly make the first quarter of the image. I figured the way to do this was to adjust
for (int y = 0; y < imageHeight; y++) //Rows!
{
for (int x = 0; x < imageWidth; x++) //Columns! (pixels in every row)
{
to
for (int y = 0; y < halfHeight; y++) //Rows!
{
for (int x = 0; x < halfWidth; x++) //Columns! (pixels in every row)
{
However, instead of drawing the top left quarter as I suspected, the program drew along the full width, repeating itself after the halfway mark of the image width was reached, and only drew along a quarter of the height
(see image)
As I like to learn from my mistakes, I'd love to know what exactly is going wrong here.
Thank you for helping a programming greenhorn out :)
Full program code below.
#include "stdafx.h"
#include <fstream>
#include <iostream>
int imageWidth = 512, imageHeight = 512, maxN = 255, halfWidth = 256, halfHeight = 256;
double minR = -1.5, maxR = 0.7, minI = -1.0, maxI = 1.0;
std::ofstream f_out("output_image.ppm");
int findMandelbrot(double cr, double ci, int max_iterations)
{
int i = 0;
double zr = 0.0, zi = 0.0;
while (i < max_iterations && zr * zr + zi * zi < 4.0)
{
double temp = zr * zr - zi * zi + cr;
zi = 2.0 * zr * zi + ci;
zr = temp;
i++;
}
return i;
}
double mapToReal(int x, int imageWidth, double minR, double maxR)
{
double range = maxR - minR;
return x * (range / imageWidth) + minR;
}
double mapToImaginary(int y, int imageHeight, double minI, double maxI)
{
double range = maxI - minI;
return y * (range / imageHeight) + minI;
}
void threadedMandelbrot()
{
for (int y = 0; y < halfHeight; y++) //Rows!
{
for (int x = 0; x < halfWidth; x++) //Columns! (pixels in every row)
{
//... Find the real and imaginary values of c, corresponding
// to that x,y pixel in the image
double cr = mapToReal(x, imageWidth, minR, maxR);
double ci = mapToImaginary(y, imageHeight, minI, maxI);
//... Find the number of iterations in the Mandelbrot formula
// using said c.
int n = findMandelbrot(cr, ci, maxN);
//... Map the resulting number to an RGB value.
int r = (n % 256);
int g = (n % 256);
int b = (n % 256);
//... Output it to the image
f_out << r << " " << g << " " << b << " ";
}
f_out << std::endl;
}
}
int main()
{
//Initializes file
f_out << "P3" << std::endl;
f_out << imageWidth << " " << imageHeight << std::endl;
f_out << "256" << std::endl;
//For every pixel...
threadedMandelbrot();
f_out.close();
std::cout << "Helemaal klaar!" << std::endl;
return 0;
}
Your are calculating only a quarter of the image, so you have to set the dimension of that to halfHeight, halfWidth or fill the file with zeroes. When the image viewer reads the file, it shows two lines of it in a single line of pixels untill it reaches the end of the file, at a quarter of the picture height.
To fix the problem you just have to calculate the other three quarters of the image, but I suggest you to seperate the calc function from the file writing function: do the threaded calcs putting the result in an array (std::array or std::vector), look up the right color and then write to file.
Related
I am learning FBP and for the last 1 month, I am stuck on Backprojection Algorithm. I have done the following steps till now.
Create Sinogram (Radon Transform)
Create Filter (hanning Filter: i used the hanning window function to implement the filter)
I know Ram filter works the best but I want to research how a different high pass filter will work on this.
Fast Fourier Transform.(using dft function)
Apply the filter
Inverse Fourier Transform(using dft function)
Pass the filtered sinogram through the backprojection algorithm.
I am sharing 2 functions here:
Traditional Backprojection Algorithm (Found From LOC: 29)
Mat backprojectionTraditional(Mat inversefft) {
Mat reconstruction(inversefft.size(), CV_32F);
int numOfAngles = 180;
int dtheta = 180 / numOfAngles;
for (int x = 0; x < reconstruction.size().height; x++) {
double delta_t = M_PI / 180;
for (int y = 0; y < reconstruction.size().width; y++) {
reconstruction.at<float>(x, y) = 0.0;
for (int theta = 0; theta < inversefft.size().width; theta += dtheta) {
int s = (x - 0.5 * inversefft.size().height) * sin(theta * delta_t) +
(y - 0.5 * inversefft.size().height) * cos(theta * delta_t) + 0.5 * inversefft.size().height;
if (s > 0 && s < inversefft.size().height) {
reconstruction.at<float>(x, y) += inversefft.at<float>(s, theta);
}
}
if (reconstruction.at<float>(x, y) < 0)reconstruction.at<float>(x, y) = 0;
}
}
rotate(reconstruction, reconstruction, ROTATE_90_CLOCKWISE);
return reconstruction;
}
The Iterative way as found in one book Page-72
Mat backprojectionIterative(Mat inversefft)
{
Mat iradon(inversefft.size(), CV_32F);
Mat projection(inversefft.size(), CV_32F);
float colsum;
for (int z = 0; z < 180; z++) {
projection = imrotate(inversefft, z);
//imshow("Projected image", projection);
//waitKey(0);
for (int i = 0; i < inversefft.size().width; i++) {
colsum = 0;
for (int j = 0; j < inversefft.size().height; j++) {
colsum += projection.at<float>(j, i);
//cout << colsum << endl;
}
for (int k = 0; k < inversefft.size().height; k++) {
//cout << "Break" << endl;
//cout << colsum << endl;
//cout << iradon.at<float>(k, i) << endl;
iradon.at<float>(k, i) += colsum;
//cout << iradon.at<float>(k, i) << endl;
}
}
//iradon = imrotate(iradon, 90);
//normalize(iradon, iradon, 0, 1, NORM_MINMAX, CV_32F);
//imshow("Reconstructed image", iradon);
//waitKey(0);
}
return iradon;
}
Can anyone tell me how to implement the backprojection algorithm and where is my error?
Here is the test data
#P.S - This is my first question, I will fix it as soon as possible if I am not following the community standards.
Thank you.
Edit - Since most of the viewers are not understanding the problem statement, I am uploading the results of both of these functions.
After Applying the backprojectionTraditional function
After Applying the backprojectionIterative function
The output should be same or nearly close as the input after applying backprojection.
I have a problem to get a discrete Sequence of a contour.
My idea: I want to place an anchor in a middle of a closed contour in an image and use polar coordinates to get a length for each degree of the polar coordinates.
I already have created a vector of fixed length 360 and iterate through all contour points(ca. 4000) with length l=contour.length/360. Here i get 360 values along the contour with length l. But i want to have a discrete value for each integer degree from 1 to 360.
Can i interpolate my array to fix values from 1 to 360?
vector<cv::Point> cn;
double theta = 0;
double dis = 0;
int polsize = 360;
int psize = 0;
for (int k = 0; k < cnts[0].size(); k++) {
cn.push_back(cnts[0].at(k));
}
double pstep = cn.size() / polsize;
for (int m = 1; m < polsize; m++) {
psize = (int)(m * pstep);
polar(cn[psize].x, cn[psize].y, &dis, &theta);
outputFile << theta << "/" << dis << ";";
}
void polar(int x, int y, double* r, double* theta)
{
double toDegrees = 180 / 3.141593;
*r = sqrt((pow(x, 2)) + (pow(y, 2)));
double xt = x, yt = y;
yt = 1024 - yt;
if (xt == 0) xt = 0.1;
if (yt == 0) yt = 0.1;
*theta = atan(yt / xt) * toDegrees;
if (*theta < 0) *theta = *theta+180;
return;
}
You seem to miss some of the C++ basics. E.g.
1) If you use at() you add unnecessary range checking. As you are looping until cnts[0].size() you're doing that twice now.
2) you don't need to use return in void functions.
3) don't use pointers for return. This is C++, not C. Use references, or std::tuple return type.
Then you're actually replicating the std::complex type.
The code can be really simple.
#include <vector>
//#include <algorithm> // if using std::copy
#include <cmath>
#include <sstream> // only for the temporary output.
static constexpr auto toDeg = 180 / 3.141593;
struct Point{
double x,y;
double abs() const {
return std::sqrt(std::pow(x,2) + std::pow(y,2));
}
double arg() const {
return std::atan2(y, x) * toDeg;
}
};
int main(){
std::vector<std::vector<Point>> cnts = {{{1,1}}};
// copy constructor
std::vector<Point> cn(cnts[0]);
// range-based constructor
//std::vector<Point> cn(std::cbegin(cnts[0]), std::cend(cnts[0]));
// or copy-insert
//std::vector<Point> cn
//cn.reserve(cnts[0].size());
//std::copy(std::cbegin(cnts[0]), std::cend(cnts[0]), std::back_inserter(cn));
std::stringstream outputFile; // temp
for (auto const& el : cn) {
outputFile << el.arg() << "/" << el.abs() << ";";
}
}
I'm just looking for an explanation behind OpenCV's coordinate system and its pixel intensity system. I am using a for loop to find the most intense pixel on the screen (I am aware that I could use minMaxLoc to find it, however, my code will be changed to find the leftmost pixel as well so this for loop is needed).
for (int i = 0; i < imgHight; i++) //Going through the height or Y axis.
{ // The height and width are equal the image is a square
for (int j = 0; j < imgWidth; j++) // Going through the width or X axis.
{
newInten = grayImg.at<uchar>(j, i); // This uses the X and Y to find a new point
HeadInten = grayImg.at<uchar>(Head); // This uses the stored XY as a comparassion
newIntenVal = newInten.val[0]; // This finds the intensity of the pixel at this point
if (newIntenVal > LowerBounds) //Compaired to lower bounds (80% of max pixel intensity)
{
if (newIntenVal > HeadIntenVal) // If the new intensity is higher than old then change head to new point and run again.
{
//cout << newInten << " " << HeadInten << " " << i << " " << j << endl;
Head = { j, i};
HeadIntenVal = HeadInten.val[0]; // Finds the intensity of pixel at stored head.
}
}
}
}
I then draw a circle around Head to show its position on the picture. The issue is, that currently, this draws in a random place, but when Head = {i, j} (X and Y are reversed) then this draws in the expected place. Is there any suggestion as to why this might happen?
Incorrect circle :
Correct circle:
The problem feeds into trying to find the intensity of that pixel again using the point values of Head, this then gives me a different result and cannot be used for comparison later on.
Many Thanks for any help!
EDIT: Full code - Sorry its a bit of a mess
#include<opencv2/opencv.hpp>
#include<iostream>
using namespace std;
using namespace cv;
int main()
{
double IBKG, IMAX, TC, LowerBounds; // IBKG is Image Background Level
Intensity, IMAX is Maximum Image Intensity, TC is comet theshold
Point IBKG_LOC, IMAX_LOC; // These are the respective locations on the
image, head is to find the head of the comet
Mat img = imread("Test1.png");
Mat grayImg;
int imgHight = img.rows;
int imgWidth = img.cols;
cout << imgHight << " " << imgWidth << endl;
cvtColor(img, grayImg, CV_RGB2GRAY);
minMaxLoc(grayImg, &IBKG, &IMAX, &IBKG_LOC, &IMAX_LOC);
cout << IMAX_LOC << endl;
TC = (IBKG + IMAX) / 2;
LowerBounds = IMAX * 0.8;
cout << LowerBounds << endl;
uint8_t newInten;
int maxX = 0, maxY = 0;
uint8_t grayMax = grayImg.at<uint8_t>(maxY, maxX);
for (int i = 0; i < imgHight; i++) //Going through the height or Y axis.
{ // The height and width are equal the image is a square
for (int j = 0; j < imgWidth; j++) // Going through the width or X axis.
{
uint8_t newInten = grayImg.at<uchar>(i,j); // This uses the X and Y to find a new point
if (newInten > LowerBounds) //Compaired to lower bounds (80% of max pixel intensity)
{
if (newInten > grayMax) // If the new intensity is higher than old then change head to new point and run again.
{
grayMax = newInten;
maxX = j;
maxY = i;
}
}
}
}
Point LeftSide;
bool leftSideFlag = false;
for (int i = maxX; i > 0; i--)
{
newInten = grayImg.at<uchar>(maxY, i);
if (!leftSideFlag)
{
if (newInten < TC)
{
LeftSide = { maxY, i};
leftSideFlag = true;
//i = 1;
}
}
}
int CircleRadius = maxX - LeftSide.x;
circle(img, Point(maxY, maxX), 10, Scalar(255, 255, 255));
cout << IBKG <<" " << IMAX << " " << IBKG_LOC << " " << IMAX_LOC << " " << TC << endl;
namedWindow("Image", WINDOW_NORMAL);
namedWindow("Gray Image", WINDOW_NORMAL);
imshow("Image", img);
imshow("Gray Image", grayImg);
waitKey(0);
return 0;
}
The Mat.at function needs parameters row , column order.
So first Y and then X
int imgHight = grayImg.rows;
int imgWidth = grayImg.cols;
int maxX = 0, maxY = 0;
uint8_t grayMax = grayImg.at<uint8_t>(maxY,maxX);
for (int i = 0; i < imgHight; i++) //Going through the height or Y axis.
{ // The height and width are equal the image is a square
for (int j = 0; j < imgWidth; j++) // Going through the width or X axis.
{
uint8_t newInten = grayImg.at<uchar>(i, j); // This uses the X and Y to find a new point
if (newInten > grayMax)
{
grayMax = newInten;
maxX = j;
maxY = i;
}
}
}
Also changed the code a bit to make it faster.
Not the fastest possible option though.
After adding the suggested fixes I swapped the X and Y round the way I would expect them normally for drawing the circle, I also needed to remember to compare maxX to Leftside.y. The outcome is now as expected. Thank you all!
I am trying to calculate distances between particles in a box. If the distance calculated is greater than a preset cut-off distance, then the potential energy is 0. Otherwise, it is 1.
There are some rounding issues I think and I am not familiar with variable types and passing variables through functions to know what to do next.
The error
When I calculate d0 by hand I get d0 = 0.070 - this is not what the computer gets! The computer gets a number on the order of e-310.
All of the calculated distances (dij) are no shorter than 1/14, which is much larger than e-310. According to my if statement, if dij>d0, then U=0, so I should get a total energy of 0, but this is what I get:
d0 is 6.95322e-310
i is 0 j is 1 dij is 0.0714286 d0 is 6.95322e-310 Uij is 1
.....
Energy of the system is 24976
Please let me know if I could provide any more information. I did not include the entirety of my code, but the other portion involves no manipulation of d0.
I copied the relevant pieces of code below
Part 1: relevant box data
class Vector {
public:
double x;
double y;
Vector() {
}
Vector (double x_, double y_) {
x = x_;
y = y_;
}
double len() {
return sqrt(x*x + y*y);
}
double lenSqr() {
return x*x + y*y;
}
};
class Atom
{
public:
Vector pos;
Vector vel;
Vector force;
Atom (double x_, double y_) {
pos = Vector(x_, y_);
}
};
class BoxData
{
public:
const double Len = 1.;
const double LenHalf = 0.5 * Len;
long double d = 1. / 14; // d is the distance between each atom
in the initial trigonal lattice
int nu = 7; // auxillary parameter - will be varied
long double d0 = d * (1 - 2^(nu - 8)); // cutoff distance
double alpha = d - d0; // maximum allowed displacement
};
int main() {
// Initialize box
LoadBox();
// Institute a for loop here
SystemEnergy();
MonteCarloMove();
return 0;
}
//Putting atoms into box
void LoadBox()
{
ofstream myfile("init.dat", ios::out);
//Load atoms in box in triangular offset lattice
const double x_shift = 1. / 14;
const double y_shift = 1. / 16;
double x = 0;
double y = 0;
double x_offset = 0;
for (y = 0; y <= 1. - y_shift; y += y_shift) {
for (x = x_offset; x < 0.99; x += x_shift) {
// create atom in position (x, y)
// and store it in array of atoms
atoms.push_back(Atom(x, y));
}
// every new row flip offset 0 -> 1/28 -> 0 -> 1/28...
if (x_offset < x_shift / 4) {
x_offset = x_shift / 2;
} else {
x_offset = 0.0;
}
}
const int numAtoms = atoms.size();
//print the position of each atom in the file init.dat
for (int i = 0; i < numAtoms; i++) {
myfile << "x is " << atoms[i].pos.x << " y is " << atoms[i].pos.y << endl;
}
myfile.close();
}
Part 2 : Energy calculation
vector<Atom> atoms;
BoxData box_;
void SystemEnergy()
{
ofstream myfile("energy.dat", ios::out);
double box_Len, box_LenHalf, box_d0;
double dij; // distance between two atoms
double Uij; // energy between two particles
double UTotal = 0;
double pbcx, pbcy; // pbc -> periodic boundary condition
double dx, dy;
myfile << "d0 is " << box_d0 << endl;
// define the number of atoms as the size of the array of atoms
const int numAtoms = atoms.size();
//pick atoms
for (int i=0; i<numAtoms-1; i++) { // pick one atom -> "Atom a"
Atom &a = atoms[i];
for (int j=i+1; j<numAtoms; j++) { // pick another atom -> "Atom b"
Atom &b = atoms[j];
dx = a.pos.x - b.pos.x;
dy = a.pos.y - b.pos.y;
pbcx = 0.0;
pbcy = 0.0;
// enforce periodic boundary conditions
if(dx > box_LenHalf) pbcx =- box_Len;
if(dx < -box_LenHalf) pbcx =+ box_Len;
if(dy > box_LenHalf) pbcy =- box_Len;
if(dy < -box_LenHalf) pbcy =+ box_Len;
dx += pbcx;
dy += pbcy;
// calculate distance between atoms
dij = sqrt(dx*dx + dy*dy);
// compare dij to the cutoff distance to determine energy
if (dij > box_d0) {
Uij = 0;
} else {
Uij = 1;
}
myfile << "i is " << i << " j is " << j << " dij is " << dij << " d0 is " << box_d0 << " Uij is " << Uij << endl;
UTotal += Uij; // sum the energies
}
}
myfile << "Energy of the system is " << UTotal << endl;
myfile.close();
}
Sorry for the formatting issues - getting the hang of copy/pasting to the forum.
I smooth some data using a basic Exponential Moving Average filter:
int main ()
{
double a0 = 0.1;
double input = 8.0;
double z = 0.0;
for(int i=0; i < 200; i++) {
z += a0 * (input - z);
std::cout << i << "° : "<< z << std::endl;
}
}
For some reasons, I'd like to do it every X (=8) steps.
The fact is that as for now, I don't know how to calculate it every 8° input. I still process at every input and "store" only the 8°.
How would you "save CPU" avoid to calculate it on each step? Is there a series where I can just calculate 8° value ahead?
This is the actual code I have (which smooth at each step):
int main ()
{
double a0 = 0.1;
double input = 8.0;
double z = 0.0;
int step = 8;
for(int i=0; i < 200; i+=8) {
z += a0 * (input - z);
std::cout << i << "° : "<< z << std::endl;
int j = 1;
while (j++ < step) {
z += a0 * (input - z);
}
}
}
I'd like to avoid the "7 steps of while" into a unique operation. Is it possible?
It's called an exponential moving average function for a reason: the difference (input - z0) is an exponentially decreasing function of the number of steps. In fact, after N steps the decrease is pow(1-a0,N).
Now the relevant math is pow(x,N) == pow(pow(x,8), N/8).