How to write this interpolate function using OpenCV? - c++
I want to optimize this code, in particular this function:
bool interpolate(const Mat &im, float ofsx, float ofsy, float a11, float a12, float a21, float a22, Mat &res)
{
bool ret = false;
// input size (-1 for the safe bilinear interpolation)
const int width = im.cols-1;
const int height = im.rows-1;
// output size
const int halfWidth = res.cols >> 1;
const int halfHeight = res.rows >> 1;
int dim = res.rows * res.cols;
float *out = res.ptr<float>(0);
for (int j=-halfHeight; j<=halfHeight; ++j)
{
const float rx = ofsx + j * a12;
const float ry = ofsy + j * a22;
#pragma omp simd
for(int i=-halfWidth; i<=halfWidth; ++i)
{
float wx = rx + i * a11;
float wy = ry + i * a21;
const int x = (int) floor(wx);
const int y = (int) floor(wy);
if (x >= 0 && y >= 0 && x < width && y < height)
{
// compute weights
wx -= x; wy -= y;
// bilinear interpolation
*out++ =
(1.0f - wy) * ((1.0f - wx) * im.at<float>(y,x) + wx * im.at<float>(y,x+1)) +
( wy) * ((1.0f - wx) * im.at<float>(y+1,x) + wx * im.at<float>(y+1,x+1));
} else {
*out++ = 0;
ret = true; // touching boundary of the input
}
}
}
return ret;
}
Can anybody please help to find an equivalent function in OpenCV for the code above? I'm not expert on image processing, so I don't really know what the fucntion above does in details, but I think this is a warp-affine transformation, even though I don't really know how to define an OpenCV equivalent.
It seems that the input images are the blurred image, the original image or small patches of it. The output result is always a small patch.
Here are some samples:
Sample 1:
Args:
ofx=175.497 ofsy=315.06 a11=1.69477 a12=0.0671724 a21=0.0679493 a22=1.56309
Input image:
Output image:
Sample 2:
Args:
ofx=572.121 ofsy=326.659 a11=0.871508 a12=0 a21=0.346405 a22=1.14744
Input image:
Output image:
Sample 3:
ofx=66.571 ofsy=148.991 a11=1.12027 a12=0.126609 a21=0.126609 a22=2.53436
Input image:
Output image:
These are different sections of the original code where the function is called:
// warp input according to current shape matrix
interpolate(wrapper.prevBlur, lx, ly, u11*ratio, u12*ratio, u21*ratio, u22*ratio, img);
Mat smoothed(patchImageSize, patchImageSize, CV_32FC1, (void *)&workspace.front());
// interpolate with det == 1
if (!interpolate(img, x, y, a11, a12, a21, a22, smoothed))
{
// subsample with corresponding scale
interpolate(smoothed, (float)(patchImageSize>>1), (float)(patchImageSize>>1), imageToPatchScale, 0, 0, imageToPatchScale, patch);
// ok, do the interpolation
interpolate(img, x, y, a11, a12, a21, a22, patch);
This is what happens when I try to use warpAffine in the following way:
// warp input according to current shape matrix
interpolate(wrapper.prevBlur, lx, ly, u11*ratio, u12*ratio, u21*ratio, u22*ratio, img);
Mat warp_mat( 2, 3, CV_32FC1 );
Mat myPatch(img.rows, img.cols, CV_32FC1);
warp_mat.at<float>(0,2) = lx;
warp_mat.at<float>(1,2) = ly;
warp_mat.at<float>(0,0) = u11*ratio;
warp_mat.at<float>(0,1) = u12*ratio;
warp_mat.at<float>(1,0) = u21*ratio;
warp_mat.at<float>(1,1) = u22*ratio;
warpAffine(wrapper.prevBlur, myPatch, warp_mat, myPatch.size());
The resulting myPatch matrix is a zero matrix, while img (obtained by interpolate) is:
[19.109245, 19.189388, 18.941183, 18.454611, 18.285404, 19.447983, 22.037096, 28.504759, 37.753605, 50.69936, 61.34388, 67.619637, 70.699326, 71.640556, 73.347702, 72.383781, 70.7649, 72.320709, 74.32235;
18.464636, 18.408369, 18.347059, 18.194805, 17.982847, 18.312258, 18.990305, 21.852564, 26.399525, 35.10569, 44.444019, 53.986103, 59.851856, 63.937149, 67.766968, 70.979973, 73.074722, 77.097763, 82.344398;
17.838448, 17.706562, 17.580456, 17.869242, 18.216852, 18.72654, 19.004158, 20.150208, 21.66539, 26.167187, 31.805283, 41.04277, 48.207466, 54.719109, 59.793156, 65.378006, 71.004974, 77.016037, 86.317352;
17.257101, 17.117496, 16.95055, 17.34347, 18.505379, 20.129673, 21.161978, 22.195414, 22.287436, 24.150574, 26.179817, 32.619934, 39.298115, 46.696926, 52.091522, 57.986988, 64.629898, 72.434052, 82.955505;
16.810595, 16.665813, 16.672272, 17.16098, 18.665346, 21.783976, 24.785789, 27.150511, 27.23918, 27.834826, 27.594404, 30.645121, 35.405987, 42.133587, 46.915634, 51.880707, 57.028702, 64.57579, 74.402069;
16.687065, 16.451401, 16.626608, 17.460049, 19.36956, 23.552647, 28.802736, 33.788773, 35.505379, 35.85894, 34.729523, 34.880505, 37.088661, 42.075432, 45.702, 49.056709, 51.509052, 56.637093, 63.660839;
16.802176, 16.594761, 16.863697, 18.126085, 20.491119, 25.517574, 32.737259, 40.572498, 45.324429, 46.528313, 45.586109, 44.153858, 43.667118, 46.450905, 48.539593, 50.182858, 50.18359, 51.575584, 54.267056;
17.036257, 17.025221, 17.271259, 18.925261, 22.124079, 27.620583, 35.921772, 46.177872, 54.232437, 57.583233, 57.648571, 55.857315, 53.885891, 54.148857, 55.00872, 54.9893, 52.946201, 50.873283, 49.034798;
17.337849, 17.61212, 18.028404, 19.572941, 23.455297, 29.841951, 38.668663, 49.819805, 60.617371, 66.327873, 68.025574, 66.935631, 64.995117, 63.513988, 63.28405, 62.325748, 58.940784, 53.796066, 48.033508;
17.798275, 18.203262, 19.018663, 20.718761, 24.611408, 31.378065, 40.706932, 51.637016, 63.323963, 71.373169, 74.578476, 74.412659, 74.106857, 72.411026, 71.710922, 70.007111, 66.181709, 58.721882, 50.149853;
18.593805, 19.017687, 20.172789, 22.093014, 25.971659, 32.813194, 41.989246, 52.252911, 62.929924, 71.418938, 76.355003, 77.044289, 78.709656, 78.83432, 78.581551, 76.614075, 72.71788, 63.598377, 52.698578;
19.567734, 20.197411, 21.640959, 24.039509, 27.603041, 34.091061, 42.821777, 52.127884, 61.030842, 68.610733, 73.860558, 75.530617, 78.25412, 81.30085, 82.840904, 80.822067, 76.685196, 67.430412, 54.54921;
21.115396, 21.835562, 23.40497, 26.244884, 30.036913, 35.568745, 43.308716, 51.656746, 58.69318, 64.595673, 69.845467, 72.11985, 74.878944, 79.890228, 83.964821, 82.866249, 77.71666, 68.196243, 55.256557;
23.264105, 24.024746, 25.705564, 28.513554, 32.514004, 37.26601, 43.47644, 50.611153, 56.786697, 61.13575, 66.052094, 69.762238, 71.692001, 76.810669, 81.848129, 82.157066, 76.844963, 66.500725, 54.042095;
26.102678, 26.758638, 28.201065, 30.806498, 34.584103, 38.752495, 43.416939, 48.890656, 54.433743, 58.482693, 63.515507, 69.373245, 71.917755, 74.965172, 78.791039, 79.034378, 73.354454, 62.917992, 50.983219;
29.008026, 30.016344, 30.787025, 32.692429, 35.850079, 39.365425, 42.956245, 46.993965, 51.688225, 56.120068, 61.624519, 69.804024, 74.923134, 76.170395, 76.252747, 74.715118, 68.599701, 58.000847, 47.082359;
31.630077, 33.315144, 33.247631, 33.903202, 36.094364, 38.939133, 42.000217, 45.338474, 49.197887, 53.639317, 59.658398, 69.140472, 77.870468, 79.725624, 75.932251, 69.885872, 62.522583, 52.486378, 42.571148;
34.113537, 36.435402, 35.544792, 34.225368, 35.189747, 37.445477, 40.579632, 44.427345, 48.191299, 52.085419, 57.660496, 66.887024, 77.807755, 81.70005, 76.676743, 66.486168, 56.192219, 46.825108, 38.276539;
37.42725, 39.82682, 37.698589, 34.016525, 33.155304, 35.16758, 39.039139, 44.336964, 49.359722, 52.590809, 56.610603, 64.08419, 74.419289, 80.603294, 76.006302, 63.653465, 50.843102, 41.247444, 34.471062]
Update after comment:
These are results by using [[1, 0, 0], [0, 1, 0]] with the following code:
Mat warp_mat( 2, 3, CV_32FC1 );
Mat myPatch(img.rows, img.cols, CV_32FC1);
warp_mat.at<float>(0,0) = 1; //u11*ratio
warp_mat.at<float>(0,1) = 0; //u12*ratio
warp_mat.at<float>(0,2) = 0+(img.cols >> 1); //lx
warp_mat.at<float>(1,0) = 0; //u21*ratio
warp_mat.at<float>(1,1) = 1; //u22*ratio
warp_mat.at<float>(1,2) = 0+(img.rows >> 1); //ly
warpAffine(wrapper.prevBlur, myPatch, warp_mat, myPatch.size());
interpolate(wrapper.prevBlur, 0, 0, 1, 0, 0, 1, img);
std::cout<<"img="<<std::endl<<img<<std::endl;
std::cout<<"myPatch="<<std::endl<<myPatch<<std::endl;
The result is the same, but if I try to use:
warp_mat.at<float>(0,0) = 1; //u11*ratio
warp_mat.at<float>(0,1) = 1; //u12*ratio
warp_mat.at<float>(0,2) = 0+(img.cols >> 1); //lx
warp_mat.at<float>(1,0) = 0; //u21*ratio
warp_mat.at<float>(1,1) = 1; //u22*ratio
warp_mat.at<float>(1,2) = 0+(img.rows >> 1); //ly
warpAffine(wrapper.prevBlur, myPatch, warp_mat, myPatch.size());
interpolate(wrapper.prevBlur, 0, 0, 1, 1, 0, 1, img);
The matrix are "mirrored":
myPatch=
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0;
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0;
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0;
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0;
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0;
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0;
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0;
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0;
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0;
0, 0, 0, 0, 0, 0, 0, 0, 0, 2.4431293, 2.1086276, 1.7749974, 1.5721301, 1.5403291, 1.6410155, 1.8406107, 2.1113796, 2.3246853, 2.274801;
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2.3276107, 2.0702307, 1.8100098, 1.6615094, 1.6572961, 1.7410251, 1.8701531, 2.0462515, 2.1933937;
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2.3676813, 2.1666555, 1.9666147, 1.8710723, 1.9005303, 1.9753534, 2.0355756, 2.1005828;
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2.4378726, 2.2967758, 2.1802788, 2.1628339, 2.2288194, 2.2786529, 2.2584724;
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2.3656359, 2.3085568, 2.3188434, 2.4140301, 2.513881, 2.5077794;
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2.206573, 2.20857, 2.3185263, 2.5056028, 2.6312659;
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2.1686711, 2.1401191, 2.2343175, 2.4260342;
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2.3495517, 2.2178252, 2.1930335;
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2.6443374, 2.4216607;
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2.8480706]
img=
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0;
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0;
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0;
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0;
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0;
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0;
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0;
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0;
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0;
0, 0, 0, 0, 0, 0, 0, 0, 0, 2.4431293, 2.1086276, 1.7749974, 1.5721301, 1.5403291, 1.6410155, 1.8406107, 2.1113796, 2.3246853, 2.274801;
0, 0, 0, 0, 0, 0, 0, 0, 2.3276107, 2.0702307, 1.8100098, 1.6615094, 1.6572961, 1.7410251, 1.8701531, 2.0462515, 2.1933937, 2.1447542, 1.8548106;
0, 0, 0, 0, 0, 0, 0, 2.3676813, 2.1666555, 1.9666147, 1.8710723, 1.9005303, 1.9753534, 2.0355756, 2.1005828, 2.1541297, 2.0949042, 1.8804716, 1.6108752;
0, 0, 0, 0, 0, 0, 2.4378726, 2.2967758, 2.1802788, 2.1628339, 2.2288194, 2.2786529, 2.2584724, 2.2164674, 2.1899939, 2.1344388, 2.0028977, 1.8055484, 1.6097167;
0, 0, 0, 0, 0, 2.3656359, 2.3085568, 2.3188434, 2.4140301, 2.513881, 2.5077794, 2.3889487, 2.2654738, 2.21731, 2.2129889, 2.1711345, 2.027447, 1.7903067, 1.5879864;
0, 0, 0, 0, 2.206573, 2.20857, 2.3185263, 2.5056028, 2.6312659, 2.5770819, 2.3866575, 2.2314539, 2.2230167, 2.3092971, 2.3504019, 2.2321868, 1.9485472, 1.637617, 1.494508;
0, 0, 0, 2.1686711, 2.1401191, 2.2343175, 2.4260342, 2.566293, 2.5228219, 2.3388758, 2.2057574, 2.2558136, 2.4211838, 2.5120842, 2.3888607, 2.0588915, 1.6645602, 1.4044838, 1.4204007;
0, 0, 2.3495517, 2.2178252, 2.1930335, 2.3035395, 2.4375367, 2.446404, 2.3236551, 2.2328601, 2.3145993, 2.5046468, 2.5949829, 2.4436085, 2.0789487, 1.6472976, 1.3386253, 1.3225981, 1.6233296;
0, 2.6443374, 2.4216607, 2.271126, 2.2733064, 2.367074, 2.4035037, 2.3307135, 2.2715025, 2.3534446, 2.5142543, 2.558598, 2.3710468, 2.0039113, 1.6069642, 1.3526549, 1.3859948, 1.7268054, 2.1843567;
2.8480706, 2.6081781, 2.4022317, 2.3262172, 2.3576505, 2.3759208, 2.3233094, 2.2885542, 2.3600159, 2.4632583, 2.4390275, 2.2265964, 1.9053584, 1.6181513, 1.4964664, 1.6123655, 1.9332824, 2.2962041, 2.4815767]
And finally using:
warp_mat.at<float>(0,0) = 0; //u11*ratio
warp_mat.at<float>(0,1) = 1; //u22*ratio
warp_mat.at<float>(0,2) = 0+(img.cols >> 1); //lx
warp_mat.at<float>(1,0) = 1; //u21*ratio
warp_mat.at<float>(1,1) = 1; //u22*ratio
warp_mat.at<float>(1,2) = 0+(img.rows >> 1); //ly
I get:
myPatch=
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0;
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0;
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0;
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0;
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0;
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0;
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0;
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0;
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0;
0, 0, 0, 0, 0, 0, 0, 0, 0, 2.4431293, 0, 0, 0, 0, 0, 0, 0, 0, 0;
0, 0, 0, 0, 0, 0, 0, 0, 0, 2.1086276, 2.3276107, 0, 0, 0, 0, 0, 0, 0, 0;
0, 0, 0, 0, 0, 0, 0, 0, 0, 1.7749974, 2.0702307, 2.3676813, 0, 0, 0, 0, 0, 0, 0;
0, 0, 0, 0, 0, 0, 0, 0, 0, 1.5721301, 1.8100098, 2.1666555, 2.4378726, 0, 0, 0, 0, 0, 0;
0, 0, 0, 0, 0, 0, 0, 0, 0, 1.5403291, 1.6615094, 1.9666147, 2.2967758, 2.3656359, 0, 0, 0, 0, 0;
0, 0, 0, 0, 0, 0, 0, 0, 0, 1.6410155, 1.6572961, 1.8710723, 2.1802788, 2.3085568, 2.206573, 0, 0, 0, 0;
0, 0, 0, 0, 0, 0, 0, 0, 0, 1.8406107, 1.7410251, 1.9005303, 2.1628339, 2.3188434, 2.20857, 2.1686711, 0, 0, 0;
0, 0, 0, 0, 0, 0, 0, 0, 0, 2.1113796, 1.8701531, 1.9753534, 2.2288194, 2.4140301, 2.3185263, 2.1401191, 2.3495517, 0, 0;
0, 0, 0, 0, 0, 0, 0, 0, 0, 2.3246853, 2.0462515, 2.0355756, 2.2786529, 2.513881, 2.5056028, 2.2343175, 2.2178252, 2.6443374, 0;
0, 0, 0, 0, 0, 0, 0, 0, 0, 2.274801, 2.1933937, 2.1005828, 2.2584724, 2.5077794, 2.6312659, 2.4260342, 2.1930335, 2.4216607, 2.8480706]
img=
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0;
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0;
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0;
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0;
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0;
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0;
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0;
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0;
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0;
0, 0, 0, 0, 0, 0, 0, 0, 0, 2.4431293, 2.3276107, 2.3676813, 2.4378726, 2.3656359, 2.206573, 2.1686711, 2.3495517, 2.6443374, 2.8480706;
0, 0, 0, 0, 0, 0, 0, 0, 2.1086276, 2.0702307, 2.1666555, 2.2967758, 2.3085568, 2.20857, 2.1401191, 2.2178252, 2.4216607, 2.6081781, 2.6495261;
0, 0, 0, 0, 0, 0, 0, 1.7749974, 1.8100098, 1.9666147, 2.1802788, 2.3188434, 2.3185263, 2.2343175, 2.1930335, 2.271126, 2.4022317, 2.4685297, 2.4485474;
0, 0, 0, 0, 0, 0, 1.5721301, 1.6615094, 1.8710723, 2.1628339, 2.4140301, 2.5056028, 2.4260342, 2.3035395, 2.2733064, 2.3262172, 2.3705757, 2.3652363, 2.3247712;
0, 0, 0, 0, 0, 1.5403291, 1.6572961, 1.9005303, 2.2288194, 2.513881, 2.6312659, 2.566293, 2.4375367, 2.367074, 2.3576505, 2.3551981, 2.3311026, 2.2715149, 2.1814501;
0, 0, 0, 0, 1.6410155, 1.7410251, 1.9753534, 2.2786529, 2.5077794, 2.5770819, 2.5228219, 2.446404, 2.4035037, 2.3759208, 2.3474753, 2.3124287, 2.240618, 2.1282687, 2.0381868;
0, 0, 0, 1.8406107, 1.8701531, 2.0355756, 2.2584724, 2.3889487, 2.3866575, 2.3388758, 2.3236551, 2.3307135, 2.3233094, 2.3084226, 2.2854021, 2.2117574, 2.088321, 1.9926676, 1.9839712;
0, 0, 2.1113796, 2.0462515, 2.1005828, 2.2164674, 2.2654738, 2.2314539, 2.2057574, 2.2328601, 2.2715025, 2.2885542, 2.2938819, 2.2722201, 2.1820612, 2.0477793, 1.957217, 1.954851, 2.0058911;
0, 2.3246853, 2.1933937, 2.1541297, 2.1899939, 2.21731, 2.2230167, 2.2558136, 2.3145993, 2.3534446, 2.3600159, 2.3450513, 2.2874477, 2.1686828, 2.0435023, 1.9943975, 2.0270162, 2.0777535, 2.1049571;
2.274801, 2.1447542, 2.0949042, 2.1344388, 2.2129889, 2.3092971, 2.4211838, 2.5046468, 2.5142543, 2.4632583, 2.3841665, 2.2811179, 2.1669631, 2.1026075, 2.1358697, 2.2212756, 2.2625117, 2.2268343, 2.180846]
I think you basically answered yourself and it looks like a basic affine transformation.
The equivelent in OpenCV is warpAffine.
In the flags of the function you can give it any of the InterpolationFlags.
The transformation matrix M at your case will be:
[[a11, a12, ofsx],
[a21, a22, ofsy]
The output size is also a parameter, dependes on your numbers.
And if you want to optimize it as you say, you can compile OpenCV with CUDA support and then you could use the GPU version of this function.
Related
Reverse an array with preprocessor
I want to use pre-processor to fill some arrays in some ways. I can use preprocessor only for newly declared arrays. However, I need to change the array p which I declared and used before. Time optimization is very important for my purpose. #define Reverse(x) {x[63], x[62], x[61], x[60], x[59], x[58], x[57], x[56], x[55], x[54], x[53], x[52], x[51], x[50], x[49], x[48], x[47], x[46], x[45], x[44], x[43], x[42], x[41], x[40], x[39], x[38], x[37], x[36], x[35], x[34], x[33], x[32], x[31], x[30], x[29], x[28], x[27], x[26], x[25], x[24], x[23], x[22], x[21], x[20], x[19], x[18], x[17], x[16], x[15], x[14], x[13], x[12], x[11], x[10], x[9], x[8], x[7], x[6], x[5], x[4], x[3], x[2], x[1], x[0] } int main() { int p[64] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; int q[64] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; //doThings p= Reverse(q); // line A - Gives error int s[64] = Reverse(q); // line B - Works properly //doThings } I got this error: Error 11 error C3079: an initializer-list cannot be used as the right operand of this assignment operator c:\users\ferda\documents\visual studio 2013\projects\consoleapplication3\consoleapplication3\consoleapplication3.cpp 393 1 ConsoleApplication3
Built in array type does not allow to assign to it another array or use aggregate initialization on already initialized array, you would have to use memcpy or for loop to update it with new values. Your code will compile if you use std::array instead. It provides operator=: operator= (implicitly declared) overwrites every element of the array with the corresponding element of another array (public member function) http://coliru.stacked-crooked.com/a/8e664210b7f7f73b i am not sure if this will work as fast as you expect, gcc will generate lots of mov instructions : https://godbolt.org/g/tzUqC3. I suppose it might be faster to use a for loop which will require less cache memory. As always profile your code.
Translating array pointer access from C++ to Delphi
I'd like to know if I translated a piece of code correctly from C++ to Delphi. It looks like it is working, but I have a feeling that I'm reading and writing into memory that I'm not supposed to using Delphi. Given C++ code: struct tile_map { int32 CountX; int32 CountY; uint32 *Tiles; }; inline uint32 GetTileValueUnchecked(tile_map *TileMap, int32 TileX, int32 TileY) { uint32 TileMapValue = TileMap->Tiles[TileY*TileMap->CountX + TileX]; return(TileMapValue); } uint32 Tiles00[9][17] = { {1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1}, {1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1}, {1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1}, {1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1}, {1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1}, {1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1}, {1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1}, {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, }; // More tile map declarations ... // uint32 Tiles01[9][17] = ... // uint32 Tiles10[9][17] = ... // uint32 Tiles11[9][17] = ... tile_map TileMaps[2][2]; TileMaps[0][0].CountX = 17; TileMaps[0][0].CountY = 9; TileMaps[0][0].Tiles = (uint32 *)Tiles00; TileMaps[0][1] = TileMaps[0][0]; TileMaps[0][1].Tiles = (uint32 *)Tiles01; TileMaps[1][0] = TileMaps[0][0]; TileMaps[1][0].Tiles = (uint32 *)Tiles10; TileMaps[1][1] = TileMaps[0][0]; TileMaps[1][1].Tiles = (uint32 *)Tiles11; // Usage int32 PlayerTileX = 2; int32 PlayerTileY = 2; uint32 TileMapValue = GetTileValueUnchecked(&TileMap[1][1], PlayerTileX, PlayerTileY); Delphi translation: program Project1; {$APPTYPE CONSOLE} type Puint32 = ^uint32; tile_map = record CountX : int32; CountY : int32; Tiles : Puint32; end; Ptile_map = ^tile_map; {$POINTERMATH ON} function GetTileValueUnchecked(TileMap : Ptile_map; TileX, TileY : int32) : uint32; inline; begin result := TileMap^.Tiles[TileY * TileMap^.CountX + TileX]; end; const //in the future these will be read from file, so const for now Tiles00: array [0..8, 0..16] of uint32 = ( (1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1), (1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1), (1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1), (1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1), (0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1), (1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1), (1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1), (1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1), (1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1) ); // More tile map declarations ... //Tiles01: array [0..8, 0..16] of uint32 = ... //Tiles10: array [0..8, 0..16] of uint32 = ... //Tiles11: array [0..8, 0..16] of uint32 = ... var TileMaps : array [0..1, 0..1] of tile_map; PlayerTileX, PlayerTileY : int32; TileMapValue : uint32; begin TileMaps[0][0].CountX := 17; TileMaps[0][0].CountY := 9; TileMaps[0][0].Tiles := Addr(Tiles00); TileMaps[0][1] := TileMaps[0][0]; TileMaps[0][1].Tiles := Addr(Tiles01); TileMaps[1][0] := TileMaps[0][0]; TileMaps[1][0].Tiles := Addr(Tiles10); TileMaps[1][1] := TileMaps[0][0]; TileMaps[1][1].Tiles := Addr(Tiles11); // Usage PlayerTileX := 2; PlayerTileY := 2; TileMapValue = GetTileValueUnchecked(#TileMaps[1][1], PlayerTileX, PlayerTileY); end.
David Heffernan's comments has been helpful and others seem to agree that the code is correct, so I will mark this as answered.
C++ Compiler Error 2086 redefinition
I have a .cpp file that must include Console.h. In the file I'm trying to create a map (used later on for a game). Error C2086: 'int nMapArray[15][20]: redefinition #include "Console.h" #include <Windows.h> #include <stdint.h> // Map dimensions #define MAP_WIDTH 20 #define MAP_HEIGHT 15 // Tile Types #define TILE_FLOOR 0 #define TILE_WALL 1 // Map declaration int nMapArray[ MAP_HEIGHT ][ MAP_WIDTH ]; // Map Layout int nMapArray[ MAP_HEIGHT ][ MAP_WIDTH ]= { { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0 }, { 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0 }, { 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0 }, { 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0 }, { 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0 }, { 0, 0, 1, 1, 0, 1, 1, 0, 0, 0, 1, 1, 0, 1, 1, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } }; I know that I'm only supposed to declare nMapArray once but I'm not sure which one to discard. If I discard int nMapArray[ MAP_HEIGHT ][ MAP_WIDTH ]; then it will generate two errors: LNK2019: unresolved external symbol and LNK1120: unresolved externals Did a bit of googling but I still can't find the fix so help would be appreciated. EDIT: Ok so following the advice of many to get rid of the first inisialisation. From here I get two errors: error LNK2019: unresolved external symbol "public: virtual class IConsole & __thiscall Win32Console::Color(unsigned short)" (?Color#Win32Console##UAEAAVIConsole##G#Z) referenced in function "void __cdecl DrawTile(int,int)" (?DrawTile##YAXHH#Z) and error LNK1120: 1 unresolved externals Full code: #include "Console.h" #include <Windows.h> #include <stdint.h> // Map dimensions #define MAP_WIDTH 20 #define MAP_HEIGHT 15 // Tile Types #define TILE_FLOOR 0 #define TILE_WALL 1 // Map Layout int nMapArray[ MAP_HEIGHT ][ MAP_WIDTH ]= { { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0 }, { 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0 }, { 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0 }, { 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0 }, { 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0 }, { 0, 0, 1, 1, 0, 1, 1, 0, 0, 0, 1, 1, 0, 1, 1, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } }; void DrawMap( void ); bool IsPassable( int x, int y ); void DrawTile( int x, int y ); int main( void ) { console.SetTitle( "Article Two Demo" ); // Declare the player's position int nPlayerX = 4; int nPlayerY = 4; // Main game loop while( true ) { // Draw the map DrawMap(); // Draw the player to the screen console.Color( RED ); console.Position( nPlayerX, nPlayerY ); console << '#'; // Input phase - Wait for the player to do something KEYPRESS sKeyPress = console.WaitForKeypress(); // Process the input switch( sKeyPress.eCode ) { // Move up case CONSOLE_KEY_UP: // Can we move to the tile above? if( IsPassable(nPlayerX, nPlayerY-1) ) { // Move up nPlayerY--; } break; // Move left case CONSOLE_KEY_LEFT: // Can we move to the tile to the left of the player? if( IsPassable(nPlayerX-1, nPlayerY) ) { // Move left nPlayerX--; } break; // Move right case CONSOLE_KEY_RIGHT: // Can we move to the tile to the right of the player if( IsPassable(nPlayerX+1, nPlayerY ) ) { // Move right nPlayerX++; } break; // Move down case CONSOLE_KEY_DOWN: // Can we move to the tile below the player? if( IsPassable(nPlayerX, nPlayerY+1) ) { // Move down nPlayerY++; } break; // Escape key case CONSOLE_KEY_ESCAPE: // Quit the program return 0; // Ignore any other keys default: break; } } // If execution gets here, the program is done return 0; } // IsPassable Function /////////////////////////////////////////////////////////////////// // // This function analyzes the coordinates of the map array specified and returns // true if the coordinate is passable (able for the player to occupy), false if not. // bool IsPassable( int x, int y ) { // Before we do anything, make darn sure that the coordinates are valid if( x < 0 || x >= MAP_WIDTH || y < 0 || y >= MAP_HEIGHT ) return false; // Store the value of the tile specified int nTileValue = nMapArray[y][x]; // Return true if it's passable if( nTileValue == TILE_FLOOR) return true; return false; } // DrawMap Function ////////////////////////////////////////////////////////////////////// // // This function draws the entire map to the screen. // void DrawMap( void ) { for( int y = 0; y < MAP_HEIGHT; y++ ) { for( int x = 0; x < MAP_WIDTH; x++ ) { DrawTile(x, y); } } } // DrawTile Function ///////////////////////////////////////////////////////////////////// // // Draws a map tile for the map coordinates specified. // void DrawTile( int x, int y ) { console.Position( x, y ); switch( nMapArray[y][x] ) { case TILE_FLOOR: console.Color( GREY ); console << '.'; break; case TILE_WALL: console.Color( GREY ); console << '#'; break; } } ////////////////////////////////////////////////////////////////////////////////////////// In Console.h I haven't put the layout in (because I'm not entirely sure how to do that).
Get rid of the first one, the one without the initialisation. That solves the compiler issue, the linker errors are another matter. The reason they appear is simply because the compilation phase is working once the double declaration is fixed. Then I suggest you post another question with more details on the linker problems.
Why is the size and values of this OpenCV Matrix incorrect?
I use the following function to return a weight matrix of values between 0 and 1 depending on how close to the center a particular matrix position is. Also after a threshold the values are all 1 (it is like plateau with the points closer to center having value 1 and points away from center after a threshold of distance linearly fall from 1 to 0 at the edges)? cv::Mat2f getWeightsMatrix(int N, int M, float r){ cv::Mat2f weights = cv::Mat2f(N,M); int i,j; for(i=0;i<N;i++){ for(j=0;j<M;j++){ if(i<=floor(N*(1-r)/2)){ if(j<=floor(M*(1-r)/2)){ weights[i][j]=((float)(i/N-j/M)/(1-r)); } else{ weights[i][j]=(2*(float)(i/N)/(1-r)); } } else if (i>=floor(N*(1+r)/2)){ if(j>=floor(M*(1+r)/2)){ weights[i][j]=(((float)((N-i)/N))-((float)((M-j)/M)))/(1-r); } else{ weights[i][j]=(2*(float)((N-i)/N)/(1-r)); } } else{ if(j<=floor(M*(1-r)/2)){ weights[i][j]=(2*(float)(j/M)/(1-r)); } else if(j>=floor(M*(1+r)/2)){ weights[i][j]=(2*(float)((M-j)/M)/(1-r)); } else{ weights[i][j]=1; } } } } cout << weights << endl; return weights; } Now my problem is that I am having some casting issues and only values 0 and 1 are being returned (no floats). Also my matrix size displayed by the cout is 20x10 when I call the function with N=10, M=10 and r=0.5. Please helP! EDIT: This is the output [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0; 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0; 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0; 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0; 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0; 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0; 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0; 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0; 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0; 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
Your matrix consists only if integers because when you do basic operations on integers, the results gets rounded automatically. For example: when you write weights[i][j]=((float)(i/N-j/M)/(1-r)); The result of i/N is rounded to a integer, j/M is also rounded to an integer, and finally, the division by (1-r) is also rounded. Your (float) cast is a good idea but it's applied too late. You can do several things: Cast inside elementary operations, for instance, float(i)/N instead of i/N Use float numbers instead of integers: write 1.0 instead of 1 Use floats inside your loops and statements For example: for(float i = 0; i < N-0.5; i++) { for(float j = 0; j < M-0.5; j++) { if(i <= floor(N*(1.0-r)/2.0)) { // ... It's important you understand that because of floating point precision, a test such as i < N might or might not pass when float i = N. This is why I did a little trick by substracting 0.5 from your loop bounds N and M.
How to scale down blocks without causing pixel overlapping
I have a bunch of blocks that needs to be drawn into a grid. Now displaying them unscaled everything is fine but when I try to scale them down to fit withing a window I get "scale-artifacts" because I use a normal scale-ratio formula and floats. Is there a way to avoid these problems ? Common example data: Original length: 200000 Scaled down to a 25x25 pixel grid (it's this small for development and debugging) The scaled down max length: 625 (25 * 25) Scale-ratio: (625 / 200000) = 0,003125 Example data 1 - overlapping, scaled blocks overwrite each other Start of block => end of block: [start, end) 1: 2100 => 2800 2: 2800 => 3600 3: 3600 => 4500 4: 4500 => 5500 Jumping over showing the output of this example because I think example 2 and 3 will get the point across. Left it in for completeness. Example data 2 - incorrect space between 2 and 3 Start of block => end of block: [start, end) 1: 960 => 1440 2: 1440 => 1920 3: 1920 => 2400 1: 960 => 1440, length: 480, scaled length: 1.5: 2: 1440 => 1920, length: 480, scaled length: 1.5: 3: 1920 => 2400, length: 480, scaled length: 1.5: pixel start, end, length 1: 3, 0, 1 2: 4, 0, 1 3: 6, 0, 1 Displayed grid: [ 0, 0, 0, 1, 2, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ] [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ] ... Example data 3 - 1 moved a step back incorrectly Start of block => end of block: [start, end) 1: 896 => 1344 2: 1344 => 1792 3: 1792 => 2240 1: 896 => 1344, length: 448, scaled length: 1.4: 2: 1344 => 1792, length: 448, scaled length: 1.4: 3: 1792 => 2240, length: 448, scaled length: 1.4: pixel start, end, length 1: 2, 0, 1 2: 4, 0, 1 3: 5, 0, 1 Displayed grid: [ 0, 0, 1, 0, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ] [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ] ... What example data 2 and 3 should have looked like: [ 0, 0, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ] [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ] ... Remember the block values are [start, end) Preemptive strike (down-voters / trollers) Remember: I'm not psychic or a mind-reader. If you want to give negative do it in a constrictive way or it is useless (i will not learn anything) and will just pollute the thread. Update #include <iostream> #include <math.h> #include <limits.h> #include <assert.h> #include <vector> #include <array> #include <utility> // pair #include <algorithm> // for_each using namespace std; const size_t width_size = 25; // 25 pixels const size_t height_size = 25; // 25 pixels const size_t grid_length = width_size * height_size; // width * height array<size_t, grid_length> grid; const size_t original_length = 200000; typedef pair<unsigned long, unsigned long> block; vector<block> test_values; void show_grid() { for (size_t y = 0; y < height_size; ++y) { const size_t start_pos_for_current_heigth = y * width_size; const size_t end_pos_for_current_heigth = start_pos_for_current_heigth + width_size; cout << "[ "; for (size_t i = start_pos_for_current_heigth; i < end_pos_for_current_heigth; ++i) { if (i + 1 < end_pos_for_current_heigth) cout << grid[i] << ", "; else cout << grid[i]; }; cout << " ]" << endl; } } void scale_and_add(const float scale) { size_t test_value_id = 1; for_each(test_values.cbegin(), test_values.cend(), [&](const block &p) { const float s_f = p.first * scale; const unsigned long s = round(s_f); const float e_f = p.second * scale; const unsigned long e = round(e_f); const unsigned long block_length = p.second - p.first; const float block_length_scaled = block_length * scale; assert(s <= grid_length); assert(e <= grid_length); cout << test_value_id << ":" << endl; cout << " " << p.first << " => " << p.second << " length: " << block_length << endl; cout << " " << s << " (" << s_f << ") => " << e << " (" << e_f << ") length: " << (e - s) << " (" << block_length_scaled << ")" << " (scaled)" << endl; for (size_t i = s; i < e; ++i) { if (grid[i] != 0) { cout << "overlapp detected !" << endl; } grid[i] = test_value_id; } ++test_value_id; }); } void reset_common() { grid.fill(0); test_values.clear(); } int main() { const float scale = ((float)grid_length / (float)original_length); cout << "scale: " << scale << " length per pixel: " << ((float)original_length / (float)grid_length) << endl; // Example data 1 /* cout << "Example data 1" << endl; test_values.push_back(make_pair(2100, 2800)); test_values.push_back(make_pair(2800, 3600)); test_values.push_back(make_pair(3600, 4500)); test_values.push_back(make_pair(4500, 5500)); scale_and_add(scale); show_grid(); reset_common(); // Example data 2 cout << "Example data 2" << endl; test_values.push_back(make_pair(960, 1440)); test_values.push_back(make_pair(1440, 1920)); test_values.push_back(make_pair(1920, 2400)); scale_and_add(scale); show_grid(); reset_common(); // Example data 3 cout << endl << "Example data 3" << endl; test_values.push_back(make_pair(896, 1344)); test_values.push_back(make_pair(1344, 1792)); test_values.push_back(make_pair(1792, 2240)); scale_and_add(scale); show_grid(); reset_common();*/ // Generated data - to quickly find the problem cout << "Generated data" << endl; auto to_op = [&](const size_t v) { return v * (original_length / grid_length) * 1.3; // 1.4 and 1.5 are also good values to show the problem }; size_t pos = 0; size_t psize = 1; // Note this value (length) and check it with the displayed one, you'll be surprised ! for (size_t g = 0; g < 10; ++g) { test_values.push_back(make_pair(to_op(pos), to_op(pos + psize))); pos += psize; } scale_and_add(scale); show_grid(); return 0; } Output: scale: 0.003125 length per pixel: 320 Generated data 1: 0 => 416 length: 416 0 (0) => 1 (1.3) length: 1 (1.3) (scaled) 2: 416 => 832 length: 416 1 (1.3) => 3 (2.6) length: 2 (1.3) (scaled) 3: 832 => 1248 length: 416 3 (2.6) => 4 (3.9) length: 1 (1.3) (scaled) 4: 1248 => 1664 length: 416 4 (3.9) => 5 (5.2) length: 1 (1.3) (scaled) 5: 1664 => 2080 length: 416 5 (5.2) => 7 (6.5) length: 2 (1.3) (scaled) 6: 2080 => 2496 length: 416 7 (6.5) => 8 (7.8) length: 1 (1.3) (scaled) 7: 2496 => 2912 length: 416 8 (7.8) => 9 (9.1) length: 1 (1.3) (scaled) 8: 2912 => 3328 length: 416 9 (9.1) => 10 (10.4) length: 1 (1.3) (scaled) 9: 3328 => 3744 length: 416 10 (10.4) => 12 (11.7) length: 2 (1.3) (scaled) 10: 3744 => 4160 length: 416 12 (11.7) => 13 (13) length: 1 (1.3) (scaled) [ 1, 2, 2, 3, 4, 5, 5, 6, 7, 8, 9, 9, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ] [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ] [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ] [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ] [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ] [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ] [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ] [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ] [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ] [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ] [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ] [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ] [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ] [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ] [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ] [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ] [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ] [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ] [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ] [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ] [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ] [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ] [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ] [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ] [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ] This code example demonstrates my problem more clearly. Interesting fact: mingw-g++, which i used to write this example, shows slightly different values. I usually use visual studio 2010 but couldn't this time because I'm not at home.
I am not sure if I am getting the problem statement but I will take a stab at it. You have ranges of information that you are displaying contigously a range is usually [a,b). Everything is fine when a and b directly represent the pixels that you are trying to draw, but you are having problems when you want to scale the whole thing. Not dealing with multiple rows of pixels, if you have two ranges R1=[a,b) and R2=[b,c) unscaled you just draw from a to b-1 and from b to c-1 and your ranges are drawn so what is the problem in the scaled case drawing from (int)(a*scale) to ((int)(b*scale)-1) and then from (int)(b*scale) to ((int)(c*scale)-1), you can use any float to int conversion, rounding, floor or ceiling and you should be ok. The next problem area would be if your scale ranges amount to less than 1 pixel, in this case you might need to detect if the size of the scaled range is 0 and carry a correction factor (in pixels) that is added at the end of the calculation. Pseudocode DrawRanges(List<Range> ranges, float scale) int carry = 0; foreach(Range range in ranges) { int newStart = ceiling(range.start*scale); int newEnd = ceiling(range.end*scale)-1; if (newStart <= newEnd) { newEnd = newStart; ++carry; } DrawRange(newStart+carry,newEnd+carry); } This will eventually fail if you have more Ranges than blocks in your scaled down grid, you would have to figure out how to drop ranges completely. In draw rang you map your index to an actual block coordinate. Does this solve your problem ?
Yeah +1 to get you back up, the question is OK. I don't know why people thing it is so fun to downvote without even leaving a comment. Well, to the question :-) Usually when drawing you have this overlapping issues and in 3D computer graphics with scanline renderers (DirectX & OpenGL for ex) they usually Skip exactly one pixel (say all on the right and down side). Maybe this can help you out. It is possible too that when the division is perfect, you don't have the artefacts so you must maybe deal with that (ie. if the value is a 'perfect integer', for example 185.000000 then don't remove the last pixel). HTH