Converting RGB to HSL in C++ - c++

Currently trying to convert RGB to HSL. Can't figure out where I'm going wrong but my H & S values shows as 0 which is the problem.
Here is what I have:
#include <iostream>
#include <cstdlib>
#include <cmath>
float Min( float fR, float fG, float fB )
{
float fMin = fR;
if (fG < fMin)
{
fMin = fG;
}
if (fB < fMin)
{
fMin = fB;
}
return fMin;
}
float Max( float fR, float fG, float fB)
{
float fMax = fR;
if (fG > fMax)
{
fMax = fG;
}
if (fB > fMax)
{
fMax = fB;
}
return fMax;
}
void RGBToHSL( int R, int G, int B, int& H, int& S, int& L )
{
int r = 100.0;
int g = 100.0;
int b = 200.0;
float fR = r / 255.0;
float fG = g / 255.0;
float fB = b / 255.0;
float fCMin = Min(fR, fG, fB);
float fCMax = Max(fR, fG, fB);
L = 50 * (fCMin + fCMax);
if (fCMin = fCMax)
{
S = 0;
H = 0;
return;
}
else if (L < 50)
{
S = 100 * (fCMax - fCMin) / (fCMax + fCMin);
}
else
{
S = 100 * (fCMax - fCMin) / (2.0 - fCMax - fCMin);
}
if (fCMax == fR)
{
H = 60 * (fG - fB) / (fCMax - fCMin);
}
if (fCMax == fG)
{
H = 60 * (fB - fR) / (fCMax - fCMin) + 120;
}
if (fCMax == fB)
{
H = 60 * (fR - fG) / (fCMax - fCMin) + 240;
}
if (H < 0)
{
H = H + 360;
}
}
Lightness value is 58 which is fine but I'm expecting to see a value of 240 for Hue and 47 for Saturation.
Any help would be highly appreciated.
Thanks.

if (fCMin = fCMax)
should be
if (fCMin == fCMax)

Related

Code compiles correctly but the image doesn't show up

I'm trying to test and animate some Clifford attractors
Seen here:
http://paulbourke.net/fractals/clifford/
I tried compiling the code taken from here.
http://paulbourke.net/fractals/clifford/paul_richards/main.cpp
The code compiles but no image file is generated.
I'm using:
Visual Studio Code
Version: 1.38.0
Commit: 3db7e09f3b61f915d03bbfa58e258d6eee843f35
Date: 2019-09-03T21:51:09.716Z
Electron: 4.2.10
Chrome: 69.0.3497.128
Node.js: 10.11.0
V8: 6.9.427.31-electron.0
OS: Linux x64 4.15.0-60-generic snap
/*
xn+1 = sin(a yn) + c cos(a xn)
yn+1 = sin(b xn) + d cos(b yn)
*/
#include <iostream>
#include <cmath>
#include <vector>
using namespace std;
// Change params only in this block
namespace {
const int width = 1600;
const int height = 1200;
const int frames = 10000;
const int iters = 10000;
const int skipIters = 10;
double sensitivity = 0.02;
const double minX = -4.0;
const double minY = minX * height / width;
const double maxX = 4.0;
const double maxY = maxX * height / width;
const double minA = acos( 1.6 / 2.0 );
const double maxA = acos( 1.3 / 2.0 );
const double minB = acos( -0.6 / 2.0 );
const double maxB = acos( 1.7 / 2.0 );
const double minC = acos( -1.2 / 2.0 );
const double maxC = acos( 0.5 / 2.0 );
const double minD = acos( 1.6 / 2.0 );
const double maxD = acos( 1.4 / 2.0 );
};
class Color {
public:
double r, g, b;
Color(const double &red = 0, const double &green = 0, const double &blue = 0) : r(red), g(green), b(blue) {
}
Color& operator+=(const Color &rhs) {
r += rhs.r;
g += rhs.g;
b += rhs.b;
return *this;
}
static Color createHue( double h ) {
h *= 6.0;
int hi = static_cast<int>( h );
double hf = h - hi;
switch( hi % 6 ) {
case 0:
return Color( 1.0 , hf, 0.0 );
case 1:
return Color( 1.0 - hf, 1.0, 0.0 );
case 2:
return Color( 0.0 , 1.0, hf );
case 3:
return Color( 0.0, 1.0 - hf, 1.0 );
case 4:
return Color( hf, 0.0, 1.0 );
case 5:
return Color( 1.0, 0.0, 1.0 - hf );
}
return Color();
}
Color operator+(const Color &rhs) const {
return Color(*this) += rhs;
}
};
int main(void) {
vector<Color> image( width * height );
for (int i = 0; i < frames; i++) {
const double p = static_cast<double>(i) / frames;
const double a = cos( minA + p * (maxA - minA) ) * 2.0;
const double b = cos( minB + p * (maxB - minB) ) * 2.0;
const double c = cos( minC + p * (maxC - minC) ) * 2.0;
const double d = cos( minD + p * (maxD - minD) ) * 2.0;
const Color curCol = Color::createHue( p );
double x = 0.0, y = 0.0;
for (int j = 0; j < iters; j++) {
double xn = sin(a * y) + c * cos(a * x);
double yn = sin(b * x) + d * cos(b * y);
x = xn;
y = yn;
if ( j < skipIters )
continue;
int xi = static_cast<int>( (x - minX) * width / (maxX - minX) );
int yi = static_cast<int>( (y - minY) * height / (maxY - minY) );
if ( xi >= 0 && xi < width &&
yi >= 0 && yi < height ) {
image[ xi + yi * width ] += curCol;
}
}
clog << "\r" << i;
}
clog << "\n";
cout
<< "P6\n"
<< width << " " << height << "\n"
<< "255\n";
for (int y = 0; y < height; y++) {
for (int x = 0; x < width; x++) {
Color &c = image[ x + y * width ];
unsigned char r = static_cast<unsigned char>( (1.0 - exp( -sensitivity * c.r )) * 255.0 );
unsigned char g = static_cast<unsigned char>( (1.0 - exp( -sensitivity * c.g )) * 255.0 );
unsigned char b = static_cast<unsigned char>( (1.0 - exp( -sensitivity * c.b )) * 255.0 );
cout << r << g << b;
}
}
return 0;
}

How to to find smallest (optimized) distance between two vectors in C++

I'm translating Python's version of 'page_dewarper' (https://mzucker.github.io/2016/08/15/page-dewarping.html) into C++. I'm going to use dlib, which is a fantastic tool, that helped me in a few optimization problems before. In line 748 of Github repo (https://github.com/mzucker/page_dewarp/blob/master/page_dewarp.py) Matt uses optimize function from Scipy, to find the minimal distance between two vectors. I think, my C++ equivalent should be solve_least_squares_lm() or solve_least_squares(). I'll give a concrete example to analyze.
My data:
a) dstpoints is a vector with OpenCV points - std::vector<cv::Point2f> (I have 162 points in this example, they are not changing),
b) ppts is also std::vector<cv::Point2f> and the same size as dstpoints.
std::vector<cv::Point2f> ppts = project_keypoints(params, input);
It is dependent on:
- dlib::column_vector 'input' is 2*162=324 long and is not changing,
- dlib::column_vector 'params' is 189 long and its values should be changed to get the minimal value of variable 'suma', something like this:
double suma = 0.0;
for (int i=0; i<dstpoints_size; i++)
{
suma += pow(dstpoints[i].x - ppts[i].x, 2);
suma += pow(dstpoints[i].y - ppts[i].y, 2);
}
I'm looking for 'params' vector that will give me the smallest value of 'suma' variable. Least squares algorithm seems to be a good option to solve it: http://dlib.net/dlib/optimization/optimization_least_squares_abstract.h.html#solve_least_squares, but I don't know if it is good for my case.
I think, my problem is that for every different 'params' vector I get different 'ppts' vector, not only single value, and I don't know if solve_least_squares function can match my example.
I must calculate residual for every point. I think, my 'list' from aforementioned link should be something like this:
(ppts[i].x - dstpoints[i].x, ppts[i].y - dstpoints[i].y, ppts[i+1].x - dstpoints[i+1].x, ppts[i+1].y - dstpoints[i+1].y, etc.)
, where 'ppts' vector depends on 'params' vector and then this problem can be solved with least squares algorithm. I don't know how to create data_samples with these assumptions, because it requires dlib::input_vector for every sample, as it is shown in example: http://dlib.net/least_squares_ex.cpp.html.
Am I thinking right?
I'm doing the same thing this days. My solution is writing a Powell Class by myself. It works, but really slowly. The program takes 2 minutes in dewarping linguistics_thesis.jpg.
I don't know what cause the program running so slowly. Maybe because of the algorithm or the code has some extra loop. I'm a Chinese student and my school only have java lessons. So it is normal if you find some extra codes in my codes.
Here is my Powell class.
using namespace std;
using namespace cv;
class MyPowell
{
public:
vector<vector<double>> xi;
vector<double> pcom;
vector<double> xicom;
vector<Point2d> dstpoints;
vector<double> myparams;
vector<double> params;
vector<Point> keypoint_index;
Point2d dst_br;
Point2d dims;
int N;
int itmax;
int ncom;
int iter;
double fret, ftol;
int usingAorB;
MyPowell(vector<Point2d> &dstpoints, vector<double> &params, vector<Point> &keypoint_index);
MyPowell(Point2d &dst_br, vector<double> &params, Point2d & dims);
MyPowell();
double obj(vector<double> &params);
void powell(vector<double> &p, vector<vector<double>> &xi, double ftol, double &fret);
double sign(double a);// , double b);
double sqr(double a);
void linmin(vector<double> &p, vector<double> &xit, int n, double &fret);
void mnbrak(double & ax, double & bx, double & cx,
double & fa, double & fb, double & fc);
double f1dim(double x);
double brent(double ax, double bx, double cx, double & xmin, double tol);
vector<double> usePowell();
void erase(vector<double>& pbar, vector<double> &prr, vector<double> &pr);
};
#include"Powell.h"
MyPowell::MyPowell(vector<Point2d> &dstpoints, vector<double>& params, vector<Point> &keypoint_index)
{
this->dstpoints = dstpoints;
this->myparams = params;
this->keypoint_index = keypoint_index;
N = params.size();
itmax = N * N;
usingAorB = 1;
}
MyPowell::MyPowell(Point2d & dst_br, vector<double>& params, Point2d & dims)
{
this->dst_br = dst_br;
this->myparams.push_back(dims.x);
this->myparams.push_back(dims.y);
this->params = params;
this->dims = dims;
N = 2;
itmax = N * 1000;
usingAorB = 2;
}
MyPowell::MyPowell()
{
usingAorB = 3;
}
double MyPowell::obj(vector<double> &myparams)
{
if (1 == usingAorB)
{
vector<Point2d> ppts = Dewarp::projectKeypoints(keypoint_index, myparams);
double total = 0;
for (int i = 0; i < ppts.size(); i++)
{
double x = dstpoints[i].x - ppts[i].x;
double y = dstpoints[i].y - ppts[i].y;
total += (x * x + y * y);
}
return total;
}
else if(2 == usingAorB)
{
dims.x = myparams[0];
dims.y = myparams[1];
//cout << "dims.x " << dims.x << " dims.y " << dims.y << endl;
vector<Point2d> vdims = { dims };
vector<Point2d> proj_br = Dewarp::projectXY(vdims, params);
double total = 0;
double x = dst_br.x - proj_br[0].x;
double y = dst_br.y - proj_br[0].y;
total += (x * x + y * y);
return total;
}
return 0;
}
void MyPowell::powell(vector<double> &x, vector<vector<double>> &direc, double ftol, double &fval)
{
vector<double> x1;
vector<double> x2;
vector<double> direc1;
int myitmax = 20;
if(N>500)
myitmax = 10;
else if (N > 300)
{
myitmax = 15;
}
double fx2, t, fx, dum, delta;
fval = obj(x);
int bigind;
for (int j = 0; j < N; j++)
{
x1.push_back(x[j]);
}
int iter = 0;
while (true)
{
do
{
do
{
iter += 1;
fx = fval;
bigind = 0;
delta = 0.0;
for (int i = 0; i < N; i++)
{
direc1 = direc[i];
fx2 = fval;
linmin(x, direc1, N, fval);
if (fabs(fx2 - fval) > delta)
{
delta = fabs(fx2 - fval);
bigind = i;
}
}
if (2.0 * fabs(fx - fval) <= ftol * (fabs(fx) + fabs(fval)) + 1e-7)
{
erase(direc1, x2, x1);
return;
}
if (iter >= itmax)
{
cout << "powell exceeding maximum iterations" << endl;
return;
}
if (!x2.empty())
{
x2.clear();
}
for (int j = 0; j < N; j++)
{
x2.push_back(2.0*x[j] - x1[j]);
direc1[j] = x[j] - x1[j];
x1[j] = x[j];
}
myitmax--;
cout << fx2 << endl;
fx2 = obj(x2);
if (myitmax < 0)
return;
} while (fx2 >= fx);
dum = fx - 2 * fval + fx2;
t = 2.0*dum*pow((fx - fval - delta), 2) - delta * pow((fx - fx2), 2);
} while (t >= 0.0);
linmin(x, direc1, N, fval);
direc[bigind] = direc1;
}
}
double MyPowell::sign(double a)//, double b)
{
if (a > 0.0)
{
return 1;
}
else
{
if (a < 0.0)
{
return -1;
}
}
return 0;
}
double MyPowell::sqr(double a)
{
return a * a;
}
void MyPowell::linmin(vector<double>& p, vector<double>& xit, int n, double &fret)
{
double tol = 1e-2;
ncom = n;
pcom = p;
xicom = xit;
double ax = 0.0;
double xx = 1.0;
double bx = 0.0;
double fa, fb, fx, xmin;
mnbrak(ax, xx, bx, fa, fx, fb);
fret = brent(ax, xx, bx, xmin, tol);
for (int i = 0; i < n; i++)
{
xit[i] = (xmin * xit[i]);
p[i] += xit[i];
}
}
void MyPowell::mnbrak(double & ax, double & bx, double & cx,
double & fa, double & fb, double & fc)
{
const double GOLD = 1.618034, GLIMIT = 110.0, TINY = 1e-20;
double val, fw, tmp2, tmp1, w, wlim;
double denom;
fa = f1dim(ax);
fb = f1dim(bx);
if (fb > fa)
{
val = ax;
ax = bx;
bx = val;
val = fb;
fb = fa;
fa = val;
}
cx = bx + GOLD * (bx - ax);
fc = f1dim(cx);
int iter = 0;
while (fb >= fc)
{
tmp1 = (bx - ax) * (fb - fc);
tmp2 = (bx - cx) * (fb - fa);
val = tmp2 - tmp1;
if (fabs(val) < TINY)
{
denom = 2.0*TINY;
}
else
{
denom = 2.0*val;
}
w = bx - ((bx - cx)*tmp2 - (bx - ax)*tmp1) / (denom);
wlim = bx + GLIMIT * (cx - bx);
if ((bx - w) * (w - cx) > 0.0)
{
fw = f1dim(w);
if (fw < fc)
{
ax = bx;
fa = fb;
bx = w;
fb = fw;
return;
}
else if (fw > fb)
{
cx = w;
fc = fw;
return;
}
w = cx + GOLD * (cx - bx);
fw = f1dim(w);
}
else
{
if ((cx - w)*(w - wlim) >= 0.0)
{
fw = f1dim(w);
if (fw < fc)
{
bx = cx;
cx = w;
w = cx + GOLD * (cx - bx);
fb = fc;
fc = fw;
fw = f1dim(w);
}
}
else if ((w - wlim)*(wlim - cx) >= 0.0)
{
w = wlim;
fw = f1dim(w);
}
else
{
w = cx + GOLD * (cx - bx);
fw = f1dim(w);
}
}
ax = bx;
bx = cx;
cx = w;
fa = fb;
fb = fc;
fc = fw;
}
}
double MyPowell::f1dim(double x)
{
vector<double> xt;
for (int j = 0; j < ncom; j++)
{
xt.push_back(pcom[j] + x * xicom[j]);
}
return obj(xt);
}
double MyPowell::brent(double ax, double bx, double cx, double & xmin, double tol = 1.48e-8)
{
const double CGOLD = 0.3819660, ZEPS = 1.0e-4;
int itmax = 500;
double a = MIN(ax, cx);
double b = MAX(ax, cx);
double v = bx;
double w = v, x = v;
double deltax = 0.0;
double fx = f1dim(x);
double fv = fx;
double fw = fx;
double rat = 0, u = 0, fu;
int iter;
int done;
double dx_temp, xmid, tol1, tol2, tmp1, tmp2, p;
for (iter = 0; iter < 500; iter++)
{
xmid = 0.5 * (a + b);
tol1 = tol * fabs(x) + ZEPS;
tol2 = 2.0*tol1;
if (fabs(x - xmid) <= (tol2 - 0.5*(b - a)))
break;
done = -1;
if (fabs(deltax) > tol1)
{
tmp1 = (x - w) * (fx - fv);
tmp2 = (x - v) * (fx - fw);
p = (x - v) * tmp2 - (x - w) * tmp1;
tmp2 = 2.0 * (tmp2 - tmp1);
if (tmp2 > 0.0)
p = -p;
tmp2 = fabs(tmp2);
dx_temp = deltax;
deltax = rat;
if ((p > tmp2 * (a - x)) && (p < tmp2 * (b - x)) &&
fabs(p) < fabs(0.5 * tmp2 * dx_temp))
{
rat = p / tmp2;
u = x + rat;
if ((u - a) < tol2 || (b - u) < tol2)
{
rat = fabs(tol1) * sign(xmid - x);
}
done = 0;
}
}
if(done)
{
if (x >= xmid)
{
deltax = a - x;
}
else
{
deltax = b - x;
}
rat = CGOLD * deltax;
}
if (fabs(rat) >= tol1)
{
u = x + rat;
}
else
{
u = x + fabs(tol1) * sign(rat);
}
fu = f1dim(u);
if (fu > fx)
{
if (u < x)
{
a = u;
}
else
{
b = u;
}
if (fu <= fw || w == x)
{
v = w;
w = u;
fv = fw;
fw = fu;
}
else if (fu <= fv || v == x || v == w)
{
v = u;
fv = fu;
}
}
else
{
if (u >= x)
a = x;
else
b = x;
v = w;
w = x;
x = u;
fv = fw;
fw = fx;
fx = fu;
}
}
if(iter > itmax)
cout << "\n Brent exceed maximum iterations.\n\n";
xmin = x;
return fx;
}
vector<double> MyPowell::usePowell()
{
ftol = 1e-4;
vector<vector<double>> xi;
for (int i = 0; i < N; i++)
{
vector<double> xii;
for (int j = 0; j < N; j++)
{
xii.push_back(0);
}
xii[i]=(1.0);
xi.push_back(xii);
}
double fret = 0;
powell(myparams, xi, ftol, fret);
//for (int i = 0; i < xi.size(); i++)
//{
// double a = obj(xi[i]);
// if (fret > a)
// {
// fret = a;
// myparams = xi[i];
// }
//}
cout << "final result" << fret << endl;
return myparams;
}
void MyPowell::erase(vector<double>& pbar, vector<double>& prr, vector<double>& pr)
{
for (int i = 0; i < pbar.size(); i++)
{
pbar[i] = 0;
}
for (int i = 0; i < prr.size(); i++)
{
prr[i] = 0;
}
for (int i = 0; i < pr.size(); i++)
{
pr[i] = 0;
}
}
I used PRAXIS library, because it doesn't need derivative information and is fast.
I modified the code a little to my needs and now it is faster than original version written in Python.

Adding unused formal parameters to C++ method results in different behavior

When I add some extra formal parameters double tmin=0.0, double tmax=0.0 to the constructor of the Ray in the code below, I always obtain a wrong image with a white top border. These formal parameters currently contribute in no way (i.e. are unused) to the code. So how is it possible to obtain a different image?
System specifications:
OS: Windows 8.1
Compiler: MSVC 2015
Code:
#include "stdafx.h"
#include <math.h>
#include <stdlib.h>
#include <stdio.h>
#include <random>
std::default_random_engine generator(606418532);
std::uniform_real_distribution<double> distribution = std::uniform_real_distribution<double>(0.0, 1.0);
double erand48(unsigned short *x) {
return distribution(generator);
}
#define M_PI 3.14159265358979323846
struct Vector3 {
double x, y, z;
Vector3(double x_ = 0, double y_ = 0, double z_ = 0) { x = x_; y = y_; z = z_; }
Vector3 operator+(const Vector3 &b) const { return Vector3(x + b.x, y + b.y, z + b.z); }
Vector3 operator-(const Vector3 &b) const { return Vector3(x - b.x, y - b.y, z - b.z); }
Vector3 operator*(double b) const { return Vector3(x*b, y*b, z*b); }
Vector3 mult(const Vector3 &b) const { return Vector3(x*b.x, y*b.y, z*b.z); }
Vector3& norm() { return *this = *this * (1 / sqrt(x*x + y*y + z*z)); }
double Dot(const Vector3 &b) const { return x*b.x + y*b.y + z*b.z; } // cross:
Vector3 operator%(Vector3&b) { return Vector3(y*b.z - z*b.y, z*b.x - x*b.z, x*b.y - y*b.x); }
};
//struct Ray { Vector3 o, d; Ray(const Vector3 &o_, const Vector3 &d_, double tmin=0.0, double tmax=0.0) : o(o_), d(d_) {} };
struct Ray { Vector3 o, d; Ray(const Vector3 &o_, const Vector3 &d_) : o(o_), d(d_) {} };
enum Reflection_t { DIFFUSE, SPECULAR, REFRACTIVE };
struct Sphere {
double rad; // radius
Vector3 p, e, f; // position, emission, color
Reflection_t reflection_t; // reflection type (DIFFuse, SPECular, REFRactive)
Sphere(double rad_, Vector3 p_, Vector3 e_, Vector3 f_, Reflection_t reflection_t) :
rad(rad_), p(p_), e(e_), f(f_), reflection_t(reflection_t) {}
double intersect(const Ray &r) const {
Vector3 op = p - r.o;
double t, eps = 1e-4, b = op.Dot(r.d), det = b*b - op.Dot(op) + rad*rad;
if (det<0) return 0; else det = sqrt(det);
return (t = b - det)>eps ? t : ((t = b + det)>eps ? t : 0);
}
};
Sphere spheres[] = {
Sphere(1e5, Vector3(1e5 + 1,40.8,81.6), Vector3(),Vector3(.75,.25,.25),DIFFUSE),//Left
Sphere(1e5, Vector3(-1e5 + 99,40.8,81.6),Vector3(),Vector3(.25,.25,.75),DIFFUSE),//Rght
Sphere(1e5, Vector3(50,40.8, 1e5), Vector3(),Vector3(.75,.75,.75),DIFFUSE),//Back
Sphere(1e5, Vector3(50,40.8,-1e5 + 170), Vector3(),Vector3(), DIFFUSE),//Frnt
Sphere(1e5, Vector3(50, 1e5, 81.6), Vector3(),Vector3(.75,.75,.75),DIFFUSE),//Botm
Sphere(1e5, Vector3(50,-1e5 + 81.6,81.6),Vector3(),Vector3(.75,.75,.75),DIFFUSE),//Top
Sphere(16.5,Vector3(27,16.5,47), Vector3(),Vector3(1,1,1)*.999, SPECULAR),//Mirr
Sphere(16.5,Vector3(73,16.5,78), Vector3(),Vector3(1,1,1)*.999, REFRACTIVE),//Glas
Sphere(600, Vector3(50,681.6 - .27,81.6),Vector3(12,12,12), Vector3(), DIFFUSE) //Lite
};
inline double clamp(double x) { return x<0 ? 0 : x>1 ? 1 : x; }
inline int toInt(double x) { return int(pow(clamp(x), 1 / 2.2) * 255 + .5); }
inline bool intersect(const Ray &r, double &t, int &id) {
double n = sizeof(spheres) / sizeof(Sphere), d, inf = t = 1e20;
for (int i = int(n); i--;) if ((d = spheres[i].intersect(r)) && d<t) { t = d; id = i; }
return t<inf;
}
Vector3 radiance(const Ray &r_, int depth_, unsigned short *Xi) {
double t; // distance to intersection
int id = 0; // id of intersected object
Ray r = r_;
int depth = depth_;
Vector3 cl(0, 0, 0); // accumulated color
Vector3 cf(1, 1, 1); // accumulated reflectance
while (1) {
if (!intersect(r, t, id)) return cl; // if miss, return black
const Sphere &obj = spheres[id]; // the hit object
Vector3 x = r.o + r.d*t, n = (x - obj.p).norm(), nl = n.Dot(r.d)<0 ? n : n*-1, f = obj.f;
double p = f.x>f.y && f.x>f.z ? f.x : f.y>f.z ? f.y : f.z; // max refl
cl = cl + cf.mult(obj.e);
if (++depth>5) if (erand48(Xi)<p) f = f*(1 / p); else return cl; //R.R.
cf = cf.mult(f);
if (obj.reflection_t == DIFFUSE) { // Ideal DIFFUSE reflection
double r1 = 2 * M_PI*erand48(Xi), r2 = erand48(Xi), r2s = sqrt(r2);
Vector3 w = nl, u = ((fabs(w.x)>.1 ? Vector3(0, 1) : Vector3(1)) % w).norm(), v = w%u;
Vector3 d = (u*cos(r1)*r2s + v*sin(r1)*r2s + w*sqrt(1 - r2)).norm();
r = Ray(x, d);
continue;
}
else if (obj.reflection_t == SPECULAR) {
r = Ray(x, r.d - n * 2 * n.Dot(r.d));
continue;
}
Ray reflRay(x, r.d - n * 2 * n.Dot(r.d));
bool into = n.Dot(nl)>0;
double nc = 1, nt = 1.5, nnt = into ? nc / nt : nt / nc, ddn = r.d.Dot(nl), cos2t;
if ((cos2t = 1 - nnt*nnt*(1 - ddn*ddn))<0) {
r = reflRay;
continue;
}
Vector3 tdir = (r.d*nnt - n*((into ? 1 : -1)*(ddn*nnt + sqrt(cos2t)))).norm();
double a = nt - nc, b = nt + nc, R0 = a*a / (b*b), c = 1 - (into ? -ddn : tdir.Dot(n));
double Re = R0 + (1 - R0)*c*c*c*c*c, Tr = 1 - Re, P = .25 + .5*Re, RP = Re / P, TP = Tr / (1 - P);
if (erand48(Xi)<P) {
cf = cf*RP;
r = reflRay;
}
else {
cf = cf*TP;
r = Ray(x, tdir);
}
continue;
}
}
int main(int argc, char *argv[]) {
int w = 512, h = 384, samps = argc == 2 ? atoi(argv[1]) / 4 : 1; // # samples
Ray cam(Vector3(50, 52, 295.6), Vector3(0, -0.042612, -1).norm()); // cam pos, dir
Vector3 cx = Vector3(w*.5135 / h), cy = (cx%cam.d).norm()*.5135, r, *c = new Vector3[w*h];
#pragma omp parallel for schedule(dynamic, 1) private(r) // OpenMP
for (int y = 0; y<h; y++) { // Loop over image rows
fprintf(stderr, "\rRendering (%d spp) %5.2f%%", samps * 4, 100.*y / (h - 1));
for (unsigned short x = 0, Xi[3] = { 0,0,y*y*y }; x<w; x++) // Loop cols
for (int sy = 0, i = (h - y - 1)*w + x; sy<2; sy++) // 2x2 subpixel rows
for (int sx = 0; sx<2; sx++, r = Vector3()) { // 2x2 subpixel cols
for (int s = 0; s<samps; s++) {
double r1 = 2 * erand48(Xi), dx = r1<1 ? sqrt(r1) - 1 : 1 - sqrt(2 - r1);
double r2 = 2 * erand48(Xi), dy = r2<1 ? sqrt(r2) - 1 : 1 - sqrt(2 - r2);
Vector3 d = cx*(((sx + .5 + dx) / 2 + x) / w - .5) +
cy*(((sy + .5 + dy) / 2 + y) / h - .5) + cam.d;
r = r + radiance(Ray(cam.o + d * 140, d.norm()), 0, Xi)*(1. / samps);
} // Camera rays are pushed ^^^^^ forward to start in interior
c[i] = c[i] + Vector3(clamp(r.x), clamp(r.y), clamp(r.z))*.25;
}
}
FILE *fp;
fopen_s(&fp, "image.ppm", "w"); // Write image to PPM file.
fprintf(fp, "P3\n%d %d\n%d\n", w, h, 255);
for (int i = 0; i<w*h; i++)
fprintf(fp, "%d %d %d ", toInt(c[i].x), toInt(c[i].y), toInt(c[i].z));
}
First Ray structure:
struct Ray { Vector3 o, d; Ray(const Vector3 &o_, const Vector3 &d_) : o(o_), d(d_) {} };
Results in:
Second Ray structure:
struct Ray { Vector3 o, d; Ray(const Vector3 &o_, const Vector3 &d_, double tmin=0.0, double tmax=0.0) : o(o_), d(d_) {} };
Results in:
The last image has a noticeable white top border which is not present in the first image.
Edit:
I used
size_t n = sizeof(spheres) / sizeof(Sphere);
Now I obtain the same images, but I also checked if the original int(n) could differ from 9 which is never the case.
Ok this is from the Debug build, which is different from the Release build.
Sounds like a memory error, looking quickly at your code I'm sceptical of this line:
for (int i = int(n); i--;) if ((d = spheres[i].intersect(r)) && d<t)
I suspect accessing sphere[i] is out of bounds, perhaps you should try sphere[i-1]. You could also try compiling your code with a compiler that adds extra code for debugging/sanitising/checking memory addresses.

Image retrieval system by Colour from the web using C++ with openframeworks

I am writing a program in C++ and openFrameworks that should hopefully implement an image retrieval system by colour matching. I have got an algorithm to find the match in a database by an rgb value. For example, if I have a database of 1000 pictures on my computer and I have a query rgb value 255,0,0 the program would look through 1000 pictures and find the closest match. However, my problem is that I want it to also look for the match on the web. I have been trying to find how to get images from websites, however, if you don't know the specific url of the image it's hard to get hold of the data. Maybe somebody has got some knowledge of how to get hold of images on websites? Ideally, the program would go on specified website and search through every webpage for the images, it would then compare each image to the query and output the closest match.
As I mentioned in my comment, it's a matter of converting from RGB colourspace to Lab* colourspace and using the euclidean distance to the average colour of the image from the database.
Here's a basic demo:
#include "testApp.h"
//ported from http://cookbooks.adobe.com/post_Useful_color_equations__RGB_to_LAB_converter-14227.html
struct Color{
float R,G,B,X,Y,Z,L,a,b;
};
#define REF_X 95.047; // Observer= 2°, Illuminant= D65
#define REF_Y 100.000;
#define REF_Z 108.883;
Color rgb2xyz(int R,int G,int B){
float r = R / 255.0;
float g = G / 255.0;
float b = B / 255.0;
if (r > 0.04045){ r = pow((r + 0.055) / 1.055, 2.4); }
else { r = r / 12.92; }
if ( g > 0.04045){ g = pow((g + 0.055) / 1.055, 2.4); }
else { g = g / 12.92; }
if (b > 0.04045){ b = pow((b + 0.055) / 1.055, 2.4); }
else { b = b / 12.92; }
r = r * 100;
g = g * 100;
b = b * 100;
//Observer. = 2°, Illuminant = D65
Color xyz;
xyz.X = r * 0.4124 + g * 0.3576 + b * 0.1805;
xyz.Y = r * 0.2126 + g * 0.7152 + b * 0.0722;
xyz.Z = r * 0.0193 + g * 0.1192 + b * 0.9505;
return xyz;
}
Color xyz2lab(float X,float Y, float Z){
float x = X / REF_X;
float y = Y / REF_X;
float z = Z / REF_X;
if ( x > 0.008856 ) { x = pow( x , .3333333333f ); }
else { x = ( 7.787 * x ) + ( 16/116.0 ); }
if ( y > 0.008856 ) { y = pow( y , .3333333333f ); }
else { y = ( 7.787 * y ) + ( 16/116.0 ); }
if ( z > 0.008856 ) { z = pow( z , .3333333333f ); }
else { z = ( 7.787 * z ) + ( 16/116.0 ); }
Color lab;
lab.L = ( 116 * y ) - 16;
lab.a = 500 * ( x - y );
lab.b = 200 * ( y - z );
return lab;
}
Color lab2xyz(float l, float a, float b){
float y = (l + 16) / 116;
float x = a / 500 + y;
float z = y - b / 200;
if ( pow( y , 3 ) > 0.008856 ) { y = pow( y , 3 ); }
else { y = ( y - 16 / 116 ) / 7.787; }
if ( pow( x , 3 ) > 0.008856 ) { x = pow( x , 3 ); }
else { x = ( x - 16 / 116 ) / 7.787; }
if ( pow( z , 3 ) > 0.008856 ) { z = pow( z , 3 ); }
else { z = ( z - 16 / 116 ) / 7.787; }
Color xyz;
xyz.X = x * REF_X;
xyz.Y = y * REF_Y;
xyz.Z = z * REF_Z;
return xyz;
}
Color xyz2rgb(float X,float Y,float Z){
//X from 0 to 95.047 (Observer = 2°, Illuminant = D65)
//Y from 0 to 100.000
//Z from 0 to 108.883
X = ofClamp(X, 0, 95.047);
float x = X * .01;
float y = Y * .01;
float z = Z * .01;
float r = x * 3.2406 + y * -1.5372 + z * -0.4986;
float g = x * -0.9689 + y * 1.8758 + z * 0.0415;
float b = x * 0.0557 + y * -0.2040 + z * 1.0570;
if ( r > 0.0031308 ) { r = 1.055 * pow( r , ( 1 / 2.4f ) ) - 0.055; }
else { r = 12.92 * r; }
if ( g > 0.0031308 ) { g = 1.055 * pow( g , ( 1 / 2.4f ) ) - 0.055; }
else { g = 12.92 * g; }
if ( b > 0.0031308 ) { b = 1.055 * pow( b , ( 1 / 2.4f ) ) - 0.055; }
else { b = 12.92 * b; }
Color rgb;
rgb.R = round( r * 255 );
rgb.G = round( g * 255 );
rgb.B = round( b * 255 );
return rgb;
}
Color rgb2lab(int R,int G,int B){
Color xyz = rgb2xyz(R, G, B);
return xyz2lab(xyz.X, xyz.Y, xyz.Z);
}
Color lab2rgb(int L,int a,int b){
Color xyz = lab2xyz(L, a, b);
return xyz2rgb(xyz.X, xyz.Y, xyz.Z);
}
Color getAverage(ofImage img){
Color avg;
avg.L = avg.a = avg.b = 0;
int total = img.width * img.height;
for(int y = 0 ; y < img.height; y++){
for(int x = 0 ; x < img.width; x++){
ofColor c = img.getColor(x, y);
Color lab = rgb2lab(c.r,c.g,c.b);
avg.L += lab.L;
avg.a += lab.a;
avg.b += lab.b;
}
}
avg.L /= total;
avg.a /= total;
avg.b /= total;
return avg;
}
ofImage images[6];
Color averages[6];
ofColor averagesRGB[6];
ofImage colorPicker;
ofColor searchClr;
int closestId = -1;
//--------------------------------------------------------------
void testApp::setup(){
colorPicker.loadImage("colormap.gif");
images[0].loadImage("red.jpg");
images[1].loadImage("green.jpg");
images[2].loadImage("blue.jpg");
images[3].loadImage("cyan.jpg");
images[4].loadImage("magenta.jpg");
images[5].loadImage("yellow.jpg");
for(int i = 0 ; i < 6; i++){
averages[i] = getAverage(images[i]);
Color avgRGB = lab2rgb(averages[i].L, averages[i].a, averages[i].b);
averagesRGB[i] = ofColor(avgRGB.R,avgRGB.G,avgRGB.B);
}
}
//--------------------------------------------------------------
void testApp::update(){
//pick a colour
searchClr = colorPicker.getColor(mouseX,mouseY-500);
//find closest - might want to that on an event
Color searchLab = rgb2lab(searchClr.r, searchClr.g, searchClr.b);
float minDist = 10000000;
for(int i = 0 ; i < 6; i++){
Color Lab = averages[i];
float dL = Lab.L - searchLab.L;
float da = Lab.a - searchLab.a;
float db = Lab.b - searchLab.b;
float dist = sqrt(dL*dL + da*da + db*db);
if(dist < minDist){
minDist = dist;
closestId = i;
}
}
}
//--------------------------------------------------------------
void testApp::draw(){
for(int i = 0 ; i < 6; i++){
//indexed image
images[i].draw(images[i].width * i, 0);
//average colour
ofPushStyle();
ofSetColor(averagesRGB[i]);
ofRect(images[i].width * i, images[i].height, images[i].width, images[i].width);
ofPopStyle();
}
ofPushStyle();
ofSetColor(searchClr);
ofRect(200,500,200,200);
ofPopStyle();
colorPicker.draw(0,500);
if(closestId >= 0){
images[closestId].draw(400, 500);
}
}
//--------------------------------------------------------------
void testApp::keyPressed(int key){
}
//--------------------------------------------------------------
void testApp::keyReleased(int key){
}
//--------------------------------------------------------------
void testApp::mouseMoved(int x, int y){
}
//--------------------------------------------------------------
void testApp::mouseDragged(int x, int y, int button){
}
//--------------------------------------------------------------
void testApp::mousePressed(int x, int y, int button){
}
//--------------------------------------------------------------
void testApp::mouseReleased(int x, int y, int button){
}
//--------------------------------------------------------------
void testApp::windowResized(int w, int h){
}
//--------------------------------------------------------------
void testApp::gotMessage(ofMessage msg){
}
//--------------------------------------------------------------
void testApp::dragEvent(ofDragInfo dragInfo){
}
The coding style isn't brilliant but it's just to illustrate the idea. Of course you would need to load the images from the url first and index the average colour in Lab* for each in a database (vector at runtime or otherwise).
The above code is also available as an Xcode project

incorrect output RGB to HSI convertion

I'm trying to convert RGB to HSI of a given image.
But i cant seem to get the correct output.
the Intensity is already right. But the Hue and Saturation kept giving the same result, -2147483648, whenever R + G + B is not equal to 765.
I checked using this calculator:
http://www.had2know.com/technology/hsi-rgb-color-converter-equations.html
and used this formulas:
http://web2.clarkson.edu/class/image_process/RGB_to_HSI.pdf
please point out what i did wrong.. Thanks.
#include <iostream>
#include <cv.h>
#include <highgui.h>
#include "rgb.h"
#include <cmath>
#include <math.h>
#include <algorithm>
using namespace std;
int main()
{
char infname[256];
cout << "Enter input image : ";
cin >> infname;
IplImage *img = cvLoadImage(infname, 0);
RgbImage pic(img);
int H = img->height;
int W = img->width;
for (int j=0;j<H;j++)
for (int i=0;i<W;i++) {
const double PI = 4.0*atan(1.0);
double norm = 0;
double R =(double) pic[j][i].r;
double G =(double) pic[j][i].g;
double B =(double) pic[j][i].b;
double omega = 0;
double intensity = 0;
double hue = 0;
double saturation = 0;
double r = 0;
double g = 0;
double b = 0;
//Intensity
intensity = (double) (R + G + B) / (3.0*255);
//norm colours
norm = sqrt(pow(r,2) + pow(g,2) + pow(b,2));
r = (double) (R / norm);
g = (double) (G / norm);
b = (double) (B / norm);
//Saturation and Hue
if (R + G + B == 765) {
saturation = 0;
hue = 0;
}
else {
double tmp = min(r, min(g, b));
saturation = 1.0 - ((3.0 * tmp)/ (double)(r + g + b));
if (saturation < 0.5 ){
saturation = 0;
}
else if (saturation >= 0.5){
saturation = 1;
}
}
if (saturation != 0) {
omega = 0.5 * ((r-g) + (r-b)) / sqrt(pow ((r-g),2) + (r-b)*(g-b));
omega = acos(omega);
if (B <= G) {
hue = omega;
}
else if (B > G) {
hue = 2 * PI - omega;
}
}
//convert it to degrees
int resultHue = (int) round((hue * 180.0) / PI);
int resultSaturation = (int) (saturation*100.0);
int resultIntensity = (int) round(intensity * 255);
cout<<"Red = "<<R<<", Green = "<<G<<", Blue = "<<B<<endl;
cout<<"Hue = "<<resultHue<<", Saturation = "<<resultSaturation<<", Intensity = "<<resultIntensity<<endl;
}
return 0;
}
You calculate norm using r, g and b, but they're always 0 at that point.
#include <iostream>
#include <cv.h>
#include <highgui.h>
#include "rgb.h"
#include <cmath>
#include <algorithm>
#include <fstream>
using namespace std;
int main()
{
char infname[256];
ofstream outputFile;
outputFile.open("RGB_HSI.txt");
cout << "Enter input image : ";
cin >> infname;
IplImage *img = cvLoadImage(infname, 0);
RgbImage pic(img);
int H = img->height;
int W = img->width;
for (int j=0;j<H;j++)
for (int i=0;i<W;i++) {
double norm = 0;
double omega = 0;
double R =(double) pic[j][i].r;
double G =(double) pic[j][i].g;
double B =(double) pic[j][i].b;
double intensity = 0;
double hue = 0;
double saturation = 0;
double r = 0;
double g = 0;
double b = 0;
int resultHue = 0;
int resultSaturation = 0;
int resultIntensity = 0;
//Intensity
intensity = (double) (R + G + B) / (3.0*255);
//norm colours
norm = sqrt((R*R) + (G*G) + (B*B));
r = (double) (R / norm);
g = (double) (G / norm);
b = (double) (B / norm);
//Saturation and Hue
if (R + G + B == 765) {
saturation = 0;
hue = 0;
}
else {
double tmp = min(r, min(g, b));
saturation = 1.0 - ((3.0 * tmp)/ (double)(r + g + b));
if (saturation < 0.5 ){
saturation = 0;
}
else if (saturation >= 0.5){
saturation = 1;
}
}
if (saturation != 0) {
omega = 0.5 * ((r-g) + (r-b)) / sqrt(((r-g) * (r-g)) + (r-b)*(g-b));
omega = acos(omega);
if (B <= G) {
hue = omega;
}
else if (B > G) {
hue = 2 * M_PI - omega;
}
}
//convert it to degrees
resultHue = (int) round((hue * 180.0) / M_PI);
resultSaturation = (int) (saturation);
resultIntensity = (int) round(intensity * 255);
if ((R == 0) && (G == 0) && ( B== 0 )) {
resultHue = 0;
resultSaturation = 0;
resultIntensity = 0;
}
outputFile<<"Red = "<<R<<", Green = "<<G<<", Blue = "<<B<<endl;
outputFile<<"Hue = "<<resultHue<<", Saturation = "<<resultSaturation<<", Intensity = "<<resultIntensity<<endl;
}
outputFile.close();
cout << "\nRGB_HSI printed as text file: RGB_HSI.text\n";
return 0;
}