I just tried to finish a problem:Path Finder #3: the Alpinist in Codewars. I had passed all basic test cases and there were any errors under my own test cases. But when i submited my solution, my code failed for random test cased. My solution of problem is graph searching based Dijkstra algorithm and priority_queue. I think there my some potential errors i didn't consider. Please help me check it. I have tried achieve it for three hours.
My solution is below.
#include <iostream>
#include <cmath>
#include <vector>
#include <queue>
using namespace std;
const int INF = 1e9;
const int WHITE = -1;
const int GRAY = 0;
const int BLACK = 1;
int path_finder(string maze)
{
int result = 0;
vector<pair<int, int>> element;
vector<vector<pair<int, int>>> altitude;
int width = (-1 + sqrt(5 + 4 * maze.size())) / 2;
auto tem = maze.find('\n');
while (tem != string::npos)
{
maze.erase(tem, 1);
tem = maze.find('\n');
}
for (int i = 0; i < width; ++i)
{
for (int j = 0; j < width; ++j)
{
altitude.push_back(element);
if (i >= 1)
altitude[i * width + j].push_back(make_pair(i * width + j - width, abs(maze[i * width + j] - maze[i * width + j - width])));
if (i < width - 1)
altitude[i * width + j].push_back(make_pair(i * width + j + width, abs(maze[i * width + j] - maze[i * width + j + width])));
if (j >= 1)
altitude[i * width + j].push_back(make_pair(i * width + j - 1, abs(maze[i * width + j] - maze[i * width + j - 1])));
if (j < width - 1)
altitude[i * width + j].push_back(make_pair(i * width + j + 1, abs(maze[i * width + j] - maze[i * width + j + 1])));
}
}
int* distance = new int[width * width];
int* state = new int[width * width];
for (int i = 0; i < width * width; ++i)
{
distance[i] = INF;
state[i] = WHITE;
}
priority_queue<pair<int, int>> unfinished;
unfinished.push(make_pair(0, 0));
state[0] = GRAY;
distance[0] = 0;
while (!unfinished.empty())
{
pair<int, int> tem = unfinished.top();
unfinished.pop();
state[tem.second] = BLACK;
if(distance[tem.second] < tem.first * (-1))
continue;
for (int i = 0; i < altitude[tem.second].size(); ++i)
{
if(state[altitude[tem.second][i].first] != BLACK)
{
unfinished.push(make_pair(-1 * altitude[tem.second][i].second, altitude[tem.second][i].first));
if (distance[tem.second] + altitude[tem.second][i].second < distance[altitude[tem.second][i].first])
{
distance[altitude[tem.second][i].first] = distance[tem.second] + altitude[tem.second][i].second;
state[altitude[tem.second][i].first] = GRAY;
}
}
}
}
result = distance[width * width - 1];
return result;
}
Here is a test case where your code has the wrong answer.
"53072\n"
"09003\n"
"29977\n"
"31707\n"
"59844"
The least cost is 13, with this path:
{1 1 0 0 0}
{0 1 0 0 0}
{0 1 1 1 1}
{0 0 0 0 1}
{0 0 0 0 1}
But your program outputs 15.
Related
So my code is suppsed to work like this:
-take in_martix of NxN elements and R factor
-it should give back a matrix of size [N-2R]*[N-2R] with each element being a sum of in_matrix elements in R radius it should work like this for N=4 R=1
Even though my code works for smaller matrixes, for bigger ones like 1024 or 2048 or even bigger R factors it gives back a matrix of 0's. Is it a problem inside my code or just my GPU can't compute more calculations ?
Code: (for testing purposes initial matrix is filled with 1's so every element of out_matrix should == (2R+1)^2
#include "cuda_runtime.h"
#include <stdio.h>
#include <iostream>
#include <cuda_profiler_api.h>
#define N 1024
#define R 128
#define K 1
#define THREAD_BLOCK_SIZE 8
using namespace std;
__global__ void MatrixStencil(int* d_tab_begin, int* d_out_begin, int d_N, int d_R, int d_K) {
int tx = threadIdx.x + blockIdx.x * blockDim.x;
int ty = threadIdx.y + blockIdx.y * blockDim.y;
int out_local = 0;
for (int col = tx; col <= tx + 2 * d_R ; col++)
for (int row = ty; row <= ty + 2 * d_R ; row++)
out_local += *(d_tab_begin + col * d_N + row);
*(d_out_begin + (tx) * (d_N - 2 * R) + ty) = out_local;
}
void random_ints(int tab[N][N]) {
for (int i = 0; i < N; i++)
for (int j = 0; j < N; j++)
tab[i][j] = 1;
}
int main() {
static int tab[N][N];
random_ints(tab);
int tab_size = sizeof(int) * N * N;
int out_size = sizeof(int) * (N - 2 * R) * (N - 2 * R);
dim3 BLOCK_SIZE(THREAD_BLOCK_SIZE, THREAD_BLOCK_SIZE);
dim3 GRID_SIZE(ceil((float)N / (float)(THREAD_BLOCK_SIZE )), ceil((float)N / (float)(THREAD_BLOCK_SIZE )));
void** d_tab;
void** d_out;
cudaMalloc((void**)&d_tab, tab_size);
cudaMalloc((void**)&d_out, out_size);
cudaMemcpyAsync(d_tab, tab, tab_size, cudaMemcpyHostToDevice);
int* d_tab_begin = (int*)(d_tab);
int* d_out_begin = (int*)(d_out);
MatrixStencil << < GRID_SIZE, BLOCK_SIZE>> > (d_tab_begin, d_out_begin, N, R, K);
int* out = (int*)malloc(out_size);
cudaMemcpyAsync(out, d_out, out_size, cudaMemcpyDeviceToHost);
cudaThreadSynchronize();
for (int col = 0; col < N - 2 * R; col++)
{
for (int row = 0; row < N - 2 * R; row++)
{
cout << *(out + ((col * (N - 2 * R)) + row)) << " ";
}
cout << endl;
}
}
Finally thanks to Robert I found how to make the code work - by adding if statment
if ((tx < d_N - 2 * d_R) && (ty < d_N - 2 * d_R)) {
for (int col = tx; col <= tx + 2 * d_R; col++)
for (int row = ty; row <= ty + 2 * d_R; row++)
out_local += *(d_tab_begin + col * d_N + row);
*(d_out_begin + (tx) * (d_N - 2 * R) + ty) = out_local;
}
I'm trying to create a class that can procedurally create prisms (or cylinders if the precision is high enough) but only the sides of the 3d model are showing (not the top and bottom). This is using openGL and c++. Not going for efficiency, just modifying a previous class that made a sphere.
#define numSlices 2
Prism::Prism() {
init(3);
}
Prism::Prism(int prec) {
init(prec);
}
float Prism::toRadians(float degrees) { return (degrees * 2.0f * 3.14159f) / 360.0f; }
void Prism::init(int prec) {
prec = (prec < 3) ? 3 : prec;
numVertices = (prec + 1) * (numSlices+1);
numIndices = prec * numSlices * 6;
for (int i = 0; i < numVertices; i++) { vertices.push_back(glm::vec3()); }
for (int i = 0; i < numVertices; i++) { texCoords.push_back(glm::vec2()); }
for (int i = 0; i < numVertices; i++) { normals.push_back(glm::vec3()); }
for (int i = 0; i < numVertices; i++) { tangents.push_back(glm::vec3()); }
for (int i = 0; i < numIndices; i++) { indices.push_back(0); }
// calculate triangle vertices
for (int i = 0; i <= numSlices; i++) {
for (int j = 0; j <= prec; j++) {
float y = i;
float x = -(float)cos(toRadians(j * 360.0f / (float)prec));
float z = (float)sin(toRadians(j * 360.0f / (float)prec));
vertices[i * (prec + 1) + j] = glm::vec3(x, y, z);
texCoords[i * (prec + 1) + j] = glm::vec2(((float)j / prec), ((float)i / numSlices));
}
}
// calculate triangle indices
for (int i = 0; i < numSlices; i++) {
for (int j = 0; j < prec; j++) {
indices[6 * (i * prec + j) + 0] = i * (prec + 1) + j;
indices[6 * (i * prec + j) + 1] = i * (prec + 1) + j + 1;
indices[6 * (i * prec + j) + 2] = (i + 1) * (prec + 1) + j;
indices[6 * (i * prec + j) + 3] = i * (prec + 1) + j + 1;
indices[6 * (i * prec + j) + 4] = (i + 1) * (prec + 1) + j + 1;
indices[6 * (i * prec + j) + 5] = (i + 1) * (prec + 1) + j;
}
}
}
Any tips or solutions that stick closely to the code already written would much appreciated.
To render the top and bottom of the cylinder, you can create a "triangle fan" that starts from a vertex at the center of the top/bottom of the cylinder and creates one triangle for every side.
Adapting your code: (untested, I may have made mistakes against winding order)
int bottom_center = vertices.length(); vertices.push_back(glm::vec3(0,0,0));
int top_center = vertices.length(); vertices.push_back(glm::vec3(0,numSlices,0));
// Bottom
for (int j = 0; j < prec; j++) {
int base = 0;
indices.push_back(bottom_center);
indices.push_back(base+j);
indices.push_back(base+j+1);
}
// Top
for (int j = 0; j < prec; j++) {
int base = numSlices * (prec+1);
indices.push_back(top_center);
indices.push_back(base+j);
indices.push_back(base+j+1);
}
See http://www.songho.ca/opengl/gl_cylinder.html for a more worked-out example.
I want to find dominant N colors on the picture. For this purpose I decided to use KMeans algorithm. My project written on C, that is way I used cvKMeans2 algorithm. But it gives me very strange results. Then I decided to try kmeans algorithm on OpenCV C++. It gives me more accurate results. So, where is my fault? Could someone explain it to me?
1. I used this image for test.
2. Implementation on C.
#include <cv.h>
#include <highgui.h>
#define CLUSTERS 3
int main(int argc, char **argv) {
const char *filename = "test_12.jpg";
IplImage *tmp = cvLoadImage(filename);
if (!tmp) {
return -1;
}
IplImage *src = cvCloneImage(tmp);
cvCvtColor(tmp, src, CV_BGR2RGB);
CvMat *samples = cvCreateMat(src->height * src->width, 3, CV_32F);
for (int i = 0; i < samples->height; i++) {
samples->data.fl[i * 3 + 0] = (uchar) src->imageData[i * 3 + 0];
samples->data.fl[i * 3 + 1] = (uchar) src->imageData[i * 3 + 1];
samples->data.fl[i * 3 + 2] = (uchar) src->imageData[i * 3 + 2];
}
CvMat *labels = cvCreateMat(samples->height, 1, CV_32SC1);
CvMat *centers = cvCreateMat(CLUSTERS, 3, CV_32FC1);
int flags = 0;
int attempts = 5;
cvKMeans2(samples, CLUSTERS, labels,
cvTermCriteria(CV_TERMCRIT_ITER | CV_TERMCRIT_EPS, 10000, 0.005),
attempts, 0, flags, centers);
int rows = 40;
int cols = 300;
IplImage *des = cvCreateImage(cvSize(cols, rows), 8, 3);
int part = 4000;
int r = 0;
int u = 0;
for (int y = 0; y < 300; ++y) {
for (int x = 0; x < 40; ++x) {
if (u >= part) {
r++;
part = (r + 1) * part;
}
des->imageData[(300 * x + y) * 3 + 0] = static_cast<char>(centers->data.fl[r * 3 + 0]);
des->imageData[(300 * x + y) * 3 + 1] = static_cast<char>(centers->data.fl[r * 3 + 1]);
des->imageData[(300 * x + y) * 3 + 2] = static_cast<char>(centers->data.fl[r * 3 + 2]);
u++;
}
}
IplImage *dominant_colors = cvCloneImage(des);
cvCvtColor(des, dominant_colors, CV_BGR2RGB);
cvNamedWindow("dominant_colors", CV_WINDOW_AUTOSIZE);
cvShowImage("dominant_colors", dominant_colors);
cvWaitKey(0);
cvDestroyWindow("dominant_colors");
cvReleaseImage(&src);
cvReleaseImage(&des);
cvReleaseMat(&labels);
cvReleaseMat(&samples);
return 0;
}
3. Implementation on C++.
#include <cv.h>
#include <opencv/cv.hpp>
#define CLUSTERS 3
int main(int argc, char **argv) {
const cv::Mat &tmp = cv::imread("test_12.jpg");
cv::Mat src;
cv::cvtColor(tmp, src, CV_BGR2RGB);
cv::Mat samples(src.rows * src.cols, 3, CV_32F);
for (int y = 0; y < src.rows; y++)
for (int x = 0; x < src.cols; x++)
for (int z = 0; z < 3; z++)
samples.at<float>(y + x * src.rows, z) = src.at<cv::Vec3b>(y, x)[z];
int attempts = 5;
cv::Mat labels;
cv::Mat centers;
kmeans(samples, CLUSTERS, labels, cv::TermCriteria(CV_TERMCRIT_ITER | CV_TERMCRIT_EPS, 1000, 0.005),
attempts, cv::KMEANS_PP_CENTERS, centers);
cv::Mat colors(cv::Size(CLUSTERS * 100, 30), tmp.type());
int p = 100;
int cluster_id = 0;
for (int x = 0; x < CLUSTERS * 100; x++) {
for (int y = 0; y < 30; y++) {
if (x >= p) {
cluster_id++;
p = (cluster_id + 1) * 100;
}
colors.at<cv::Vec3b>(y, x)[0] = static_cast<uchar>(centers.at<float>(cluster_id, 0));
colors.at<cv::Vec3b>(y, x)[1] = static_cast<uchar>(centers.at<float>(cluster_id, 1));
colors.at<cv::Vec3b>(y, x)[2] = static_cast<uchar>(centers.at<float>(cluster_id, 2));
}
}
cv::Mat dominant_colors;
cv::cvtColor(colors, dominant_colors, CV_RGB2BGR);
cv::imshow("dominant_colors", dominant_colors);
cv::waitKey(0);
return 0;
}
4. Result of code on C.
5. Result of code on C++.
I found my mistake. It is related to IplImage's widthStep field. As I read here widthStep gets padded up to a multiple of 4 for performance reasons. If widthStep is equal to 30 it will padded up to 32.
int h = src->height;
int w = src->width;
int c = 3;
int delta = 0;
for (int i = 0, y = 0; i < h; ++i) {
for (int j = 0; j < w; ++j) {
for (int k = 0; k < c; ++k, y++) {
samples->data.fl[i * w * c + c * j + k] = (uchar) src->imageData[delta + i * w * c + c * j + k];
}
}
delta += src->widthStep - src->width * src->nChannels;
}
With pointers
for (int x = 0, i = 0; x < src->height; ++x) {
auto *ptr = (uchar *) (src->imageData + x * src->widthStep);
for (int y = 0; y < src->width; ++y, i++) {
for (int j = 0; j < 3; ++j) {
samples->data.fl[i * 3 + j] = ptr[3 * y + j];
}
}
}
#include "opencv2/core/core.hpp"
#include "opencv2/imgproc/imgproc.hpp"
#include "opencv2/highgui/highgui.hpp"
#include <math.h>
#include <fstream>
#include <iostream>
using namespace cv;
using namespace std;
#define ATD at<double>
Mat average_pooling2x2(Mat mat, int padding_mathed)
{
int width_remain = mat.cols % 2;
int high_remain = mat.rows % 2;
Mat mat_new;
if (width_remain == 0 && high_remain == 0)
mat.copyTo(mat_new);
else
{
if (padding_mathed == 1)//valid
{
Rect roi = Rect(0, 0, mat.cols - width_remain, mat.rows - high_remain);
mat(roi).copyTo(mat_new);
}
else //same
{
mat.copyTo(mat_new);
if (high_remain != 0)
{
Mat row_add = cv::Mat::zeros(high_remain, mat_new.cols,mat_new.type());
mat_new.push_back(row_add);
}
if (width_remain != 0)
{
Mat col_add = cv::Mat::zeros(width_remain, mat_new.rows, mat_new.type());
mat_new = mat_new.t();
mat_new.push_back(col_add);
mat_new = mat_new.t();
}
}
}
Mat res(mat_new.cols / 2, mat_new.rows / 2, mat_new.type(), Scalar::all(0));
if (mat_new.channels() ==3)
{
for (int i = 0; i < res.rows; i++)//this is where error happened
{
uchar *data_res = res.ptr<uchar>(i);
uchar * data = mat_new.ptr<uchar>(2*i);
uchar * data1 = mat_new.ptr<uchar>(2*i+1);
for (int j = 0; j < res.cols*res.channels(); j = j + 3)
{
data_res[j] = (data[j*2] + data[j*2+3] + data1[j*2] + data1[j*2+3]) / 4;
data_res[j + 1] = (data[j*2+1] + data[j*2+4] + data1[j*2+1] + data1[j*2+4]) / 4;
data_res[j + 2] = (data[j*2+2] + data[j*2+5] + data1[j*2+2] + data1[j*2+5]) / 4;
}
}
}
else
{
for (int i = 0; i<res.rows; i++)
{
for (int j = 0; j<res.cols; j++)
{
Mat temp;
Rect roi = Rect(j * 2, i * 2, 2, 2);
mat_new(roi).copyTo(temp);
double val;
val = sum(temp)[0] / (2 * 2);
res.ATD(i, j) = val;
}
}
}
return res;
}
int main(int argc, char** argv)
{
Mat image = imread("C://Users//Administrator//Desktop//11.jpg");
imshow("???", image);
Mat pooling_image;
average_pooling2x2(image, 2).copyTo(pooling_image);
imshow("???", pooling_image);
waitKey();
return 0;
}
OpenCV Error: Assertion failed (y == 0 || (data && dims >= 1 && (unsigned)y < (unsigned)size.p[0])) in cv::Mat::ptr, file d:\opencv\build\include\opencv2\core\mat.inl.hpp, line 827
reccently I try to implement the average pooling using C++, this is the error when I run the code, it seems that maybe the ptr pointer is out of range. but I just can not figure out where is the problem. Really need some help
If you opened the file that the error message references to, you would see that the ptr() method is defined as follows:
template<typename _Tp> inline _Tp* Mat::ptr(int y)
{
CV_DbgAssert( y == 0 || (data && dims >= 1 && (unsigned)y < (unsigned)size.p[0]) );
return (_Tp*)(data + step.p[0]*y);
}
Everything inside CV_DbgAssert() must evaluate to true - otherwise the program is going to crash at runtime. From that condition, it is clear that you are referring to the row in your program that is outside of Mat boundaries (the variable y above).
In your case, I can see several line where the program is going to crash.
In these lines, the crash happens when i gets equal or greater than res.rows/2 (the first one will crash if res.rows is an odd number):
uchar * data = mat_new.ptr<uchar>(2*i);
uchar * data1 = mat_new.ptr<uchar>(2*i+1);
This loop will also crash, because data_res has only res.cols columns, and you allow j to reach res.cols*res.channels()-1:
for (int j = 0; j < res.cols*res.channels(); j = j + 3)
{
data_res[j] = (data[j*2] + data[j*2+3] + data1[j*2] + data1[j*2+3]) / 4;
data_res[j + 1] = (data[j*2+1] + data[j*2+4] + data1[j*2+1] + data1[j*2+4]) / 4;
data_res[j + 2] = (data[j*2+2] + data[j*2+5] + data1[j*2+2] + data1[j*2+5]) / 4;
}
Also, I believe that here:
Mat res(mat_new.cols / 2, mat_new.rows / 2, mat_new.type(), Scalar::all(0));
you may have accidentaly swapped arguments - res has mat_new.cols/2 rows, whereas I think you wanted it to be mat_new.rows/2.
This is how I managed to use a Sobel Kernel on a GRAYSCALE image.However,I dont actually get how to modify it for a color image.
void Soble()
{
Mat img;
int w = 3;
int k = w / 2;
char fname[MAX_PATH];
openFileDlg(fname);
img = imread(fname, CV_LOAD_IMAGE_GRAYSCALE);
gaussianFiltering(img);
Mat destinationImg = img.clone();
float sobelY[3][3] = { 1, 2, 1, 0, 0, 0, -1, -2, -1 };
float sobelX[3][3] = { -1, 0, 1, -2, 0, 2, -1, 0, 1 };
for (int i = k; i < img.rows - k; i++)
{
for (int j = k; j < img.cols - k; j++)
{
float Gx = 0, Gy = 0;
for (int l = 0; l < w; l++)
{
for (int p = 0; p < w; p++)
{
Gx += img.at<uchar>(i + l - k, j + p - k)*sobelX[l][p];
Gy += img.at<uchar>(i + l - k, j + p - k)*sobelY[l][p];
}
}
destinationImg.at<uchar>(i, j) = sqrt(Gx*Gx + Gy * Gy) / (4 * sqrt(2));
}
}
imshow("Intermediar",destinationImg);
imshow("Initial", img);
waitKey(0);
}
I thought of using each RGB chanel but it does not work and even give some errors.
float GxR = 0, GyR = 0;
float GxG = 0, GyG = 0;
float GxB = 0, GyB = 0;
for (int l = 0; l < w; l++)
{
for (int p = 0; p < w; p++)
{
GxR += img.at<Vec3b>[0](i + l - k, j + p - k)*sobelX[l][p];
GxG += img.at<Vec3b>[1](i + l - k, j + p - k)*sobelX[l][p];
GxB += img.at<Vec3b>[2](i + l - k, j + p - k)*sobelX[l][p];
GyR += img.at<Vec3b>[0](i + l - k, j + p - k)*sobelY[l][p];
GyG += img.at<Vec3b>[1](i + l - k, j + p - k)*sobelY[l][p];
GyB += img.at<Vec3b>[2](i + l - k, j + p - k)*sobelY[l][p];
}
}
destinationImg.at<Vec3b>[0](i, j) = sqrt(GxR*GxR + GyR * GyR) / (4 * sqrt(2));
destinationImg.at<Vec3b>[1](i, j) = sqrt(GxG*GxG + GyB * GyB) / (4 * sqrt(2));
destinationImg.at<Vec3b>[2](i, j) = sqrt(GxG*GxG + GyG * GyG) / (4 * sqrt(2));
Can you please explain how can this code must be rewritten?
You access the image data the wrong way.
destinationImg.at<Vec3b>[0](i, j)
destinationImg is a Mat of type Vec3b. That means it's a 2d array of three dimensional vectors.
You'r [ ] operator is in the wrong place...
The subscript error message tells you that you're using that operator on something that is neither a pointer nor an array which is not possible.
You get the other error message because you have that operator where the (i,j) is expected.
First you have to get one of these vectors, then you can get its elements.
destinationImg.at<Vec3b>(i,j) will give you the vector at i,j.
destinationImg.at<Vec3b>(i,j)[0] will give you the first element of that vector.
Example from the OpenCV documentation:
Vec3b intensity = img.at<Vec3b>(y, x);
uchar blue = intensity.val[0];
uchar green = intensity.val[1];
uchar red = intensity.val[2];
http://docs.opencv.org/2.4.13.2/doc/user_guide/ug_mat.html