Yogang Singh
Yogang Singh

Reputation: 47

error LNK2019: unresolved external symbol Visual Studio 2013 with openCV

I am using OpenCV 2.4.10 with Visual Studio 2013 for my code. But I am getting the following linking error:

1>Pathfinding.obj : error LNK2019: unresolved external symbol "public: class cv::Vec & __cdecl cv::Mat::at >(int,int)" (??$at@V?$Vec@E$02@cv@@@Mat@cv@@QEAAAEAV?$Vec@E$02@1@HH@Z) referenced in function "private: struct Pathfinding::Point2A * __cdecl Pathfinding::GetNeighbors(struct Pathfinding::Point2A,int &)" (?GetNeighbors@Pathfinding@@AEAAPEAUPoint2A@1@U21@AEAH@Z)

1>C:\Users\ysingh\Documents\DstarLite\OpenCV\Astar\x64\Debug\Astar.exe : fatal error LNK1120: 1 unresolved externals ========== Build: 0 succeeded, 1 failed, 0 up-to-date, 0 skipped ==========

Here is the header file (please see struct Point2A in class definition) where the above error is referring to:

#include<opencv2\core\core.hpp>
#include<opencv2\imgproc\imgproc.hpp>
#include<cmath>
#include<vector>
#include<queue>
#include<map>
#include<string>



class Pathfinding
{
private :
//Two dimensional , integer -based point structure , contains additional variables for pathfinding calculation

**struct Point2A**
{
    // x, y the coordinates of the point
    //dir is the direction from the previous point . see directions coding below

    int x, y, dir;


    //level: the cost of route from start to this point
    //fscore: the essence of the A* algorithm, value is : [level] + [in air distance from destination] * astar_weight

    float fScore, level;

    //Constructors
    Point2A() : x(0), y(0), fScore(0), dir(0){};
    Point2A(int _x, int _y, float _level = 0.f, int _dir = 0) :x(_x), y(_y), level(_level), fScore(0), dir(_dir) {};

    //== operator overload
    bool operator == (const Point2A other);

};

//CompByPos : struct used in the stl map<Point2A, Point2A> during the pathfinding
//it only contains a comparator function
//we need this, because every point is unique by position, but not by fscore

struct CompByPos
{

    bool operator()(const Point2A a, const Point2A b) const;
};

//CompByFScore : contains a comparating function, which works by fscore
//it gives priority for the smaller fScore
//used in stl priority_queue<Point2A>

struct CompByFScore
{
    bool operator()(const Point2A a, const Point2A b);
};

//mapimg is the map got, pathmap is the same, but the pixels of the path are colored
//pathmap is only valid after calculate path
//blurmap is matimg blurred with opencv function, its used in keeping away from walls

cv::Mat mapimg, pathmap, blurmap;


//astar_weight is the multiplier of A* coefficient
//wall_weight is used in keeping away from walls features

float astar_weight, wall_weight;

//no comment
Point2A start, dest;

//daigonal decides if a pixel (which is a node) has 4 or 8 neighbours
//see direction coding below
//calculated decides if the Pathfinding object has valid path for current map and settings

bool diagonal, calculated;

//mrows and mcols refers to the size of mapimg
//blursize is used in avaoiding wall avoidance feature

int mrows, mcols, blur_size;

//stores the list of directions for the path
std::string dir;


//calculated Eucledian Distance between two points a and b

float Distance(Point2A a, Point2A b);

//returns an array of the points surrounding point p
//the length of the array is not constant, because the function performs
//OnMap checks too. use arraySize ref variable to get the size of the array returned

Point2A* GetNeighbors(Point2A p, int& arraySize);

// Function sets default values
void InitValues();

//Checks if point p is wall
//Class support black and white maps, where black pixels are wall

bool IsWall(Point2A p);

//Function decides if coordinates of this point are on map or not 
bool OnMap(int x, int y);

public:

enum ErrorCodes 
{
    NoError = 0,
    NoMap,
    StartIsWall,
    DestIsWall,
    NoPath,
    AlreadyCalculated

};

static const int diagonalDirX[];
static const int diagonalDirY[];
static const int nonDiagonalDirX[];
static const int nonDiagonalDirY[];

//constructor :sets default values diagonal = true, astar coefficient 0.3
Pathfinding();

 //constructor, argument map is the map on which algorithm is implemented
Pathfinding(cv::Mat map, bool _diagonal = true);

//Set OpenCV Mat image as the map
void SetMap(cv::Mat map);

////sets the A* pathfinding coefficient. 0.f means Dijkstra's algorithm, anything else is A* (positive values recommended).
//The bigger the value, the more the algorithm steers towards the destination
//but setting it too high can result in suboptimal path
//after changing that, have to call CalculatePath again

void SetAWeight(float weight);

//if set to true, each pixel has 8 connected neighbor, else only 4 - see GetDirections() comment
//after changing that, have to call CalculatePath again
void SetDiagonal(bool _diagonal);

//sets the value of how much the algorithm tries to avoid going near walls. 
//weight: the amount the walls push away the route. default 10.f
//0.f disables the feature
//avoidZoneLevel: the size of the zone surrounding the walls, in which the upper effect works. default: 5
void SetWallWeight(float weight, int avoidZoneLevel);

//sets the start point. the coordinate system is the OpenCV/image default, the origin is the upper left corner of the image.
//start and destination points have to be set after the map image!
void SetStart(int x, int y);
void SetDestination(int x, int y);

//returns the map, on which the calculated path is marked red
//call this after CalculatePath(), otherwise returns empty map
cv::Mat GetPathMap();

// returns a std::string of numbers, which represent the directions along the path.Direction coding(relative to p) :
    //call after CalculatePath()
    //if diagonal is set to true                if diagonal == false
    //      [0] [1] [2]                                 [3]
    //      [3] [p] [4]                             [2] [p] [0]
    //      [5] [6] [7]                                 [1]
std::string GetDirections();

//evaluates the algorithm. It's a separate function because it takes some time
//check out the ErrorCodes enum to decode the returned values
ErrorCodes CalculatePath();
};

I am also attaching the .cpp for this class

#include "Pathfinding.h"

bool Pathfinding::Point2A::operator==(const Point2A other) {

return x == other.x && y == other.y;
}

bool Pathfinding::CompByPos::operator()(const Point2A a, const Point2A b) const 
{

if (a.x == b.x)
    return a.y > b.y;
else
    return a.x > b.x;
  }

bool Pathfinding::CompByFScore::operator()(const Point2A a, const Point2A b) 
    {

return a.fScore > b.fScore;
   }

float Pathfinding::Distance(Point2A a, Point2A b) 
{

float x = static_cast<float>(a.x - b.x);
float y = static_cast<float>(a.y - b.y);
return sqrtf(x*x + y*y);
 }

Pathfinding:: Point2A* Pathfinding::GetNeighbors(Point2A p, int& arraySize)
{

arraySize = 0;
uchar size;

if (diagonal)
    size = 8;
else
    size = 4;

Point2A* ret = new Point2A[size];
for (int i = 0; i < size; i++) {

    int x, y;
    if (diagonal)
   {

        x = p.x + diagonalDirX[i];
        y = p.y + diagonalDirY[i];
    }
    else 
    {
        x = p.x + nonDiagonalDirX[i];
        y = p.y + nonDiagonalDirY[i];
    }

    if (!OnMap(x, y))
        continue;

    float level = p.level + 1.f + (255 - blurmap.at<cv::Vec3b>(y, x)[2]) / 255.f * wall_weight;
    Point2A n = Point2A(x, y, level, i);

    if (diagonal && (i == 0 || i == 2 || i == 5 || i == 7))
        n.level += 0.414213f;

    ret[arraySize] = n;
    arraySize++;
}
return ret;
}

void Pathfinding::InitValues()
{

astar_weight = 0.3f;
wall_weight = 10.f;
blur_size = 11;
diagonal = true;
calculated = false;
 }

bool Pathfinding::IsWall(Point2A p) 
 {

if (mapimg.at<cv::Vec3b>(p.y, p.x) == cv::Vec3b(0, 0, 0))
    return true;
return false;
}

bool Pathfinding::OnMap(int x, int y) 
{

if (x >= 0 && y >= 0 && x < mcols && y < mrows)
    return true;
return false;
}

 const int Pathfinding::diagonalDirX[] = { -1, 0, 1, -1, 1, -1, 0, 1 };
 const int Pathfinding::diagonalDirY[] = { -1, -1, -1, 0, 0, 1, 1, 1 };
 const int Pathfinding::nonDiagonalDirX[] = { 1, 0, -1, 0 };
 const int Pathfinding::nonDiagonalDirY[] = { 0, 1, 0, -1 };

Pathfinding::Pathfinding() 
   {

InitValues();
   }

Pathfinding::Pathfinding(cv::Mat map, bool _diagonal)
 {

InitValues();
SetMap(map);
diagonal = _diagonal;
}

void Pathfinding::SetMap(cv::Mat map) 
{

if (!map.empty()) 
        {

    mapimg = map;
    calculated = false;
    mrows = map.rows;
    mcols = map.cols;
    GaussianBlur(mapimg, blurmap, cv::Size(blur_size, blur_size), 0);
       }
   }

void Pathfinding::SetAWeight(float weight)
     {

if (astar_weight != weight)  
      {

    astar_weight = weight;
    calculated = false;
       }
  }

void Pathfinding::SetDiagonal(bool _diagonal)
     {

if (diagonal != _diagonal) 
      {

    diagonal = _diagonal;
    calculated = false;
       }
  }

void Pathfinding::SetWallWeight(float weight, int avoidZoneLevel)
     {

if (wall_weight == weight && blur_size == 2 * avoidZoneLevel + 1)
    return;

wall_weight = weight;
if (avoidZoneLevel >= 0)
    blur_size = 2 * avoidZoneLevel + 1;
calculated = false;
    }

void Pathfinding::SetStart(int x, int y) 
         {

if (!mapimg.empty()) 
        {

    if (OnMap(x, y))
      {

        start = Point2A(x, y);
        calculated = false;
       }
     }
  }

void Pathfinding::SetDestination(int x, int y)  
 {

if (!mapimg.empty()) 
  {

    if (OnMap(x, y)) 
 {

        dest = Point2A(x, y);
        calculated = false;
       }
   }
  }

cv::Mat Pathfinding::GetPathMap() 
 {

if (calculated) return pathmap;
else return cv::Mat();
  }

std::string Pathfinding::GetDirections() 
 {

if (calculated) return dir;
else return std::string();
 }

Pathfinding::ErrorCodes Pathfinding::CalculatePath() 
{

if (calculated)
    return AlreadyCalculated;

if (mapimg.empty())
    return NoMap;

if (IsWall(start))
    return StartIsWall;

if (IsWall(dest))
    return DestIsWall;

dir = std::string();
mapimg.copyTo(pathmap);
int **closedSet = new int*[mrows];
float **openSet = new float*[mrows];
for (int i = 0; i < mrows; i++) {

    closedSet[i] = new int[mcols];
    openSet[i] = new float[mcols];
    for (int j = 0; j < mcols; j++) {

        closedSet[i][j] = 0;
        openSet[i][j] = -1.0f;
       }
   }

    std::priority_queue<Pathfinding::Point2A, std::vector<Point2A>, CompByFScore> openSetQue[2];
int osq = 0;
std::map <Pathfinding::Point2A, Pathfinding::Point2A, CompByPos> cameFrom;

start.fScore = Distance(start, dest);
openSetQue[osq].push(start);
openSet[start.y][start.x] = 0.0f;
while (openSetQue[osq].size() != 0) {
    Point2A current = openSetQue[osq].top();
    if (current == dest) {
        while (cameFrom.size() != 0) {

            pathmap.at<cv::Vec3b>(current.y, current.x) = cv::Vec3b(0, 0, 255);
            dir = std::to_string(current.dir) + dir;
            auto it = cameFrom.find(current);
            Point2A keytmp = current;
            if (it == cameFrom.end()) {
                for (int i = 0; i < mrows; i++) {

                    delete openSet[i];
                    delete closedSet[i];
                }
                delete openSet;
                delete closedSet;
                calculated = true;
                dir = dir.substr(1, dir.length() - 1);
                return NoError;
            }
            current = cameFrom[current];
            cameFrom.erase(keytmp);
        }
    }
    openSetQue[osq].pop();
    closedSet[current.y][current.x] = 1;
    int arraySize;
    Point2A *neighbors = GetNeighbors(current, arraySize);

    for (int i = 0; i < arraySize; i++) {

        Point2A neighbor = neighbors[i];

        if (closedSet[neighbor.y][neighbor.x] == 1)
            continue;

        if (IsWall(neighbor)) {

            closedSet[neighbor.y][neighbor.x] = 1;
            continue;
        }
        float ngScore = neighbor.level;

        if (openSet[neighbor.y][neighbor.x] == -1.0f || ngScore < openSet[neighbor.y][neighbor.x]) {

            cameFrom[neighbor] = current;
            neighbor.fScore = ngScore + Distance(neighbor, dest) * astar_weight;

            if (openSet[neighbor.y][neighbor.x] == -1.0f) {
                openSet[neighbor.y][neighbor.x] = ngScore;
                openSetQue[osq].push(neighbor);
            }
            else {
                openSet[neighbor.y][neighbor.x] = ngScore;
                while (!(neighbor == openSetQue[osq].top())) {

                    openSetQue[1 - osq].push(openSetQue[osq].top());
                    openSetQue[osq].pop();
                }
                openSetQue[osq].pop();
                if (openSetQue[osq].size() >= openSetQue[1 - osq].size()) {
                    osq = 1 - osq;
                }
                while (!openSetQue[osq].empty()) {
                    openSetQue[1 - osq].push(openSetQue[osq].top());
                    openSetQue[osq].pop();
                }
                osq = 1 - osq;
                openSetQue[osq].push(neighbor);
               }
           }
       }
    delete neighbors;
    }
return NoPath;
}

Here is my main file .cpp too :

#include"Pathfinding.h"
#include<opencv2\highgui\highgui.hpp>
#include<iostream>


Pathfinding pathfinding;
cv::Mat mapimg;


void DisplayMap()
{
cv::Mat tmp;
cv::imshow("Path", tmp);
}

int main()
{
//Open and load the map

mapimg = cv::imread("test.png");
pathfinding.SetMap(mapimg);
pathfinding.SetWallWeight(0.f, 0);
pathfinding.SetStart(1, 1);
pathfinding.SetDestination(39, 53);
pathfinding.SetDiagonal(false);
DisplayMap();

 }

I think I am using Pathfinding class twice in the definition of the functions in .cpp ( i.e. Line 29 in .cpp file > Pathfinding:: Point2A* Pathfinding::GetNeighbors(Point2A p, int& arraySize)

My intention is not to throw a bunch of codes at the people but to give them an complete picture for the problem so that people can provide me some useful suggestions. My apologies for this.

My deadlines are near and I am constrained with time. Can someone suggest me some solutions.

Upvotes: 1

Views: 3481

Answers (2)

John.A.Myer
John.A.Myer

Reputation: 75

I assume your project settings are the problem for this (your write you did a working minimalistic example, so you indeed use right libs and includes).

Please check what the include and lib paths evaluate to (check this inside the configuration site). Maybe you see they are relative paths or a makro was set wrong.

Usually, an "UNRESOLVED EXTERNAL" error means you did not link the right lib (32/64 debug/release these are 4 different combinations!) or the path to the lib is wrong.

Upvotes: 1

Rama
Rama

Reputation: 3305

See this answer,

If you DID explicitly set up linking with all the necessary libraries, but linking errors still show, you might be mixing up 64/32 bit libraries and application.

BUILD -> Configration Manager. check 'platform' is 'x64'

Check that your Project -> Properties -> VC++ Directories -> Library Directories, includes the path where the OpenCV libraries are

And Linker -> General -> Aditional Library Directories

C:\opencv\build\x64\vc11\lib

(on a 64-bit machine running VS2012, it will vary on other setups).

Upvotes: 0

Related Questions