vs2019配置opencv451d.lib中测试光线追迹遇到的一个很有意思的bug

vs版本是2019,opencv版本是451
这个问题描述起来很长,首先我先贴出代码,代码是正确的,因为我成功运行了,但是!我重新开启另一个解决方案,代码报错了
cv库链接https://github.com/FaithBook233/RayTracing.git?%ra=link 作者:FaithBook-_- https://www.bilibili.com/read/cv9008428/?from=readlist 出处:bilibili
代码有3部分

问题相关代码,请勿粘贴截图

这是main

#include <iostream>
#include "Vec3.h"
#include "Ray.h"
using namespace std;

#include <opencv.hpp>
#include <highgui.hpp>
using namespace cv;//添加OPENCV相关的头文件

bool HitSphere(const Vec3& Center, float Radius, const Ray& R)
{
    Vec3 OC = R.Origin() - Center;
    float A = Dot(R.Direction(), R.Direction());
    float B = 2.0 * Dot(OC, R.Direction());
    float C = Dot(OC, OC) - Radius * Radius;
    float Discriminant = B * B - 4 * A * C;
    return (Discriminant > 0);
}
Vec3 Color(const Ray& R)//声明一个color函数,用于计算射线R检测到的颜色,并且返回vec3表示所检测的颜色
{
    if (HitSphere(Vec3(0, 0, -1), 0.5, R))
        return Vec3(1, 0, 0);
    Vec3 UnitDirection = UnitVector(R.Direction());
    float T = 0.5 * (UnitDirection.Y() + 1.0);
    return (1.0 - T) * Vec3(1.0, 1.0, 1.0) + T * Vec3(0.5, 0.7, 1.0);
}//在color返回值中T的范围是【0,1】,T越接近1,返回的颜色越接近vec(0.5,0.7,1.0)淡蓝色,否则越接近白色

int main()
{
    int nx = 200;//图片宽度(单位为像素)
    int ny = 200;//图片高度(像素)
    //写入文件头
    std::cout << "P3" << std::endl << nx << " " << ny << std::endl << "255" << std::endl;//P3表示颜色为ASCII,255是最大颜色

    Vec3 LowerLeftCorner(-2.0, -1.0, -1.0);//设置左下角坐标
    Vec3 Horizontal(4.0, 0.0, 0.0);//屏幕水平宽度
    Vec3 Vertical(0.0, 2.0, 0.0);//屏幕垂直高度
    Vec3 Origin(0.0, 0.0, 0.0);//原点(眼睛)位置

    //预览窗口
    int WidowWidth;//窗口宽度
    int WindowHeight;//窗口高度

    if (nx > ny)//图片为横板,计算高度与宽度
    {
        WindowHeight = 1080 - 200;
        WidowWidth = (int)((double)WindowHeight * (double)nx / (double)ny);
    }
    else //图片为竖版
    {
        WidowWidth = 1920 - 200;
        WindowHeight = (int)((double)WidowWidth * (double)ny / (double)nx);
    }
    Mat RenderingImage(ny, nx, CV_8UC3, Scalar(50, 50, 50));//创建第一张图
    namedWindow(" 图像预览(渲染中)", WINDOW_NORMAL);//设置标题
    moveWindow(" 图像预览(渲染中)", (int)((1720.0 - WidowWidth) / 2), (int)((1800.0 - WindowHeight) / 2) - 50);//设置窗口位置
    resizeWindow(" 图像预览(渲染中)", WidowWidth, WindowHeight);//窗口大小

    //为了方便对小数的应用,采用double类型
    for (int j = nx - 1; j >= 0; j--)//图片的行信息(即一开始是在199层开始输出然后逐层往下)
    {
        for (int i = 0; i < nx; i++)//列信息(图片从0列开始往右输出)
        {
            //Vec3 Col(float(i) / float(nx), float(j) / float(ny), 0.2);//声明一个Col三维向量
            float U = float(i) / float(nx);
            float V = float(j) / float(ny);
            //U,V为当前渲染的像素在屏幕高度中的占比,0为屏幕的最上方,1为最下方

            Ray R(Origin, LowerLeftCorner + U * Horizontal + V * Vertical);//R为当前检测线
            Vec3 Col = Color(R);//计算R检测线遇到的颜色并由Color函数返回

            int ir = int(255.99 * Col[0]);
            int ig = int(255.99 * Col[1]);
            int ib = int(255.99 * Col[2]);//将像素的三个通道写入文件代替RGB变量
            std::cout << ir << " " << ig << " " << ib << std::endl;//将数据写入ppm文件

           //实时显示渲染帧数
            RenderingImage.at<cv::Vec3b>(ny - 1 - j, i)[0] = ib;
            RenderingImage.at<cv::Vec3b>(ny - 1 - j, i)[1] = ig;
            RenderingImage.at<cv::Vec3b>(ny - 1 - j, i)[2] = ir;
        }

        //每行计算填充完后刷新预览窗口
        if (!(j % (ny / 100)))
        {
            imshow(" 图像预览(渲染中)", RenderingImage);
            waitKey(1);//等待1毫秒后让窗口刷新出来
        }
    }
    imshow(" 图像预览(渲染中)", RenderingImage);//展示窗口
    waitKey(3000);//让窗口停留3000毫秒
    destroyAllWindows();//关闭窗口
    return 0;
}

这是vec3头文件

#pragma once
#pragma once
/*
    Vec3类为空间三维坐标或RGB颜色的抽象类
    E[3]数组为向量的具体数值

*/
#include<iostream>
#include<stdlib.h>
#include <Math.h>

class Vec3
{
public:
    Vec3() {};
    Vec3(double E0, double E1, double E2)
    {
        E[0] = E0;
        E[1] = E1;
        E[2] = E2;
    }
    //返回单个元素的值
    //作为位置
    inline double X() const { return E[0]; }
    inline double Y() const { return E[1]; }
    inline double Z() const { return E[2]; }
    //作为RGB颜色
    inline double R() const { return E[0]; }
    inline double G() const { return E[1]; }
    inline double B() const { return E[2]; }

    //以下为运算符重载
    inline const Vec3& operator+() const { return *this; }
    inline Vec3 operator-() const { return Vec3(-E[0], -E[1], -E[2]); }
    inline double operator[](int i)const { return E[i]; } //根据i获取元素
    inline double& operator[](int i) { return E[i]; }    //根据下标i获取元素引用

    inline Vec3& operator+=(const Vec3& V2);
    inline Vec3& operator-=(const Vec3& V2);
    inline Vec3& operator*=(const Vec3& V2);
    inline Vec3& operator/=(const Vec3& V2);
    inline Vec3& operator*=(const double T);
    inline Vec3& operator/=(const double T);

    //返回向量长度,即模长
    inline double Vec3Length() const {
        return sqrt(E[0] * E[0] + E[1] * E[1] + E[2] * E[2]);
    }

    //返回向量的平方
    inline double SquaredLength() const {
        return E[0] * E[0] + E[1] * E[1] + E[2] * E[2];
    }

    //获得单位向量
    inline void  MakeUnitVector();


    //以下为Vec3类的友元函数,在类内声明,类外定义,友元函数不属于任何类
    friend inline Vec3 UnitVector(Vec3 V);
    friend inline std::istream& operator>>(std::istream& IS, Vec3& T);
    friend inline std::ostream& operator<<(std::ostream& OS, const Vec3& T);
    friend inline Vec3 operator+(const Vec3& V1, const Vec3& V2);
    friend inline Vec3 operator-(const Vec3& V1, const Vec3& V2);
    friend inline Vec3 operator*(const Vec3& V1, const Vec3& V2);
    friend inline Vec3 operator/(const Vec3& V1, const Vec3& V2);
    friend inline Vec3 operator*(double T, const Vec3& V);
    friend inline Vec3 operator/(const Vec3& V, double T);
    friend inline Vec3 operator*(const Vec3& V, double T);
    friend inline double Dot(const Vec3& V1, const Vec3& V2);
    friend inline Vec3 Cross(const Vec3& V1, const Vec3& V2);

    //向量的三个元素
    double E[3];

protected:
private:

};

//以下为类的非成员函数

//输入运算符重载 ,用于输出Vec3元素数据
inline std::istream& operator>>(std::istream& IS, Vec3& T)
{
    IS >> T.E[0] >> T.E[1] >> T.E[2];
    return IS;
}
//输出运算符重载,用于输入Vec3元素数据
inline std::ostream& operator<<(std::ostream& OS, const Vec3& T)
{
    OS << T.E[0] << " " << T.E[1] << " " << T.E[2];
    return OS;
}
//获取向量的单位向量
inline void Vec3::MakeUnitVector()
{
    double k = 1.0 / sqrt(E[0] * E[0] + E[1] * E[1] + E[2] * E[2]);
    E[0] *= k;
    E[1] *= k;
    E[2] *= k;
}

inline Vec3 operator+(const Vec3& V1, const Vec3& V2)
{
    return Vec3(V1.E[0] + V2.E[0], V1.E[1] + V2.E[1], V1.E[2] + V2.E[2]);
}
inline Vec3 operator-(const Vec3& V1, const Vec3& V2)
{
    return Vec3(V1.E[0] - V2.E[0], V1.E[1] - V2.E[1], V1.E[2] - V2.E[2]);
}
inline Vec3 operator*(const Vec3& V1, const Vec3& V2)
{
    return Vec3(V1.E[0] * V2.E[0], V1.E[1] * V2.E[1], V1.E[2] * V2.E[2]);
}
inline Vec3 operator/(const Vec3& V1, const Vec3& V2)
{
    return Vec3(V1.E[0] / V2.E[0], V1.E[1] / V2.E[1], V1.E[2] / V2.E[2]);
}

inline Vec3 operator*(double T, const Vec3& V)
{
    return Vec3(T * V.E[0], T * V.E[1], T * V.E[2]);
}
inline Vec3 operator/(const Vec3& V, double T)
{
    return Vec3(V.E[0] / T, V.E[1] / T, V.E[2] / T);
}
inline Vec3 operator*(const Vec3& V, double T)
{
    return Vec3(T * V.E[0], T * V.E[1], T * V.E[2]);
}

//向量的数乘,结果是数字 C = |a|·|b|·cos(a^b);    C = a1 * b1 + a2 * b2 + a3 * b3;
inline double Dot(const Vec3& V1, const Vec3& V2)
{
    return V1.E[0] * V2.E[0] + V1.E[1] * V2.E[1] + V1.E[2] * V2.E[2];
}


//向量的叉乘,结果是一个垂直于V1V2所在平面的向量,其模长为 |a×b|=|a|·|b|·sin<a,b
inline Vec3 Cross(const Vec3& V1, const Vec3& V2)
{
    return Vec3(
        (V1.E[1] * V2.E[2] - V1.E[2] * V2.E[1]),
        (-(V1.E[0] * V2.E[2] - V1.E[2] * V2.E[0])),
        (V1.E[0] * V2.E[1] - V1.E[1] * V2.E[0])
    );
}
inline Vec3& Vec3::operator+=(const Vec3& V)
{
    E[0] += V.E[0];
    E[1] += V.E[1];
    E[2] += V.E[2];
    return *this;
}
inline Vec3& Vec3::operator*=(const Vec3& V)
{
    E[0] *= V.E[0];
    E[1] *= V.E[1];
    E[2] *= V.E[2];
    return *this;
}
inline Vec3& Vec3::operator-=(const Vec3& V)
{
    E[0] -= V.E[0];
    E[1] -= V.E[1];
    E[2] -= V.E[2];
    return *this;
}
inline Vec3& Vec3::operator/=(const Vec3& V)
{
    E[0] /= V.E[0];
    E[1] /= V.E[1];
    E[2] /= V.E[2];
    return *this;
}
inline Vec3& Vec3::operator*=(const double T)
{
    E[0] *= T;
    E[1] *= T;
    E[2] *= T;
    return *this;
}
inline Vec3& Vec3::operator/=(const double T)
{
    double K = 1.0 / T;
    E[0] *= K;
    E[1] *= K;
    E[2] *= K;
    return *this;
}

//向量/模长 = 单位方向向量
//这里可能有问题
inline Vec3 UnitVector(Vec3 V)
{
    return V / V.Vec3Length();
}

这是ray的头文件

#pragma once
#include "Vec3.h"

class Ray
{
public:
    Ray();
    Ray(const Vec3& a, const Vec3& b) { A = a, B = b; }//构造函数,初始化原点向量A和方向向量B
    Vec3 Origin() const { return A; }//返回值是原点向量A
    Vec3 Direction() const { return B; }//返回值设定为方向向量B
    Vec3 PointAtParameter(float T) const { return A + T * B; }//返回值设定为函数表达式P(t)=A+t*B,此时t表示一个实数对应光线上不同的点,A表示光线的起点,B表示光线方向
    Vec3 A;
    Vec3 B;//AB都是成员变量
};
运行结果及报错内容

这是正确的运行结果

img


这是另一个解决方案报错的结果

img

我的解答思路和尝试过的方法

因为cs是我测试用的解决方案,所以有些设置我现在也忘了,但我尝试过
1、目录是否含有中文
2、是否是空项目还是控制台应用的问题
3(这是我目前怀疑的点,但是无法验证)opencv环境配置的问题,所以我把两个解决方案的配置贴图出来
1.首先我在盘里和解决方案文件是有同样的opencv文件夹的

img

img


1.1我的系统环境配置是正确的,因为无论哪个解决方案都可以运行以下的代码

#include <iostream>
#include "Vec3.h"
using namespace std;

#include <opencv.hpp>
#include <highgui.hpp>
using namespace cv;//添加OPENCV相关的头文件

int main()
{
    int nx = 200;//图片宽度(单位为像素)
    int ny = 200;//图片高度(像素)
    //写入文件头
    std::cout << "P3" << std::endl << nx << " " << ny << std::endl << "255" << std::endl;//P3表示颜色为ASCII,255是最大颜色

    //预览窗口
    int WidowWidth;//窗口宽度
    int WindowHeight;//窗口高度
    if (nx > ny)//图片为横板,计算高度与宽度
    {
        WindowHeight = 1080 - 200;
        WidowWidth = (int)((double)WindowHeight * (double)nx / (double)ny);
    }
    else //图片为竖版
    {
        WidowWidth = 1920 - 200;
        WindowHeight = (int)((double)WidowWidth * (double)ny / (double)nx);
    }
    Mat RenderingImage(ny, nx, CV_8UC3, Scalar(50, 50, 50));//创建第一张图
    namedWindow(" 图像预览(渲染中)", WINDOW_NORMAL);//设置标题
    moveWindow(" 图像预览(渲染中)", (int)((1720.0 - WidowWidth) / 2), (int)((1800.0 - WindowHeight) / 2) - 50);//设置窗口位置
    resizeWindow(" 图像预览(渲染中)", WidowWidth, WindowHeight);//窗口大小

    //为了方便对小数的应用,采用double类型
    for (int j = nx - 1; j >= 0; j--)//图片的行信息(即一开始是在199层开始输出然后逐层往下)
    {
        for (int i = 0; i < nx; i++)//列信息(图片从0列开始往右输出)
        {
            Vec3 Col(float(i) / float(nx), float(j) / float(ny), 0.2);//声明一个Col三维向量
            int ir = int(255.99 * Col[0]);
            int ig = int(255.99 * Col[1]);
            int ib = int(255.99 * Col[2]);//将像素的三个通道写入文件代替RGB变量
            std::cout << ir << " " << ig << " " << ib << std::endl;//将数据写入ppm文件

            //元素顺序为蓝绿红
            RenderingImage.at<cv::Vec3b>(ny - 1 - j, i)[0] = ib;//蓝
            RenderingImage.at<cv::Vec3b>(ny - 1 - j, i)[1] = ig;//绿
            RenderingImage.at<cv::Vec3b>(ny - 1 - j, i)[2] = ir;//红
        }

        //每行计算填充完后刷新预览窗口
        if (!(j % (ny / 100)))
        {
            imshow(" 图像预览(渲染中)", RenderingImage);
            waitKey(1);//等待1毫秒后让窗口刷新出来
        }
    }
    imshow(" 图像预览(渲染中)", RenderingImage);//展示窗口
    waitKey(3000);//让窗口停留3000毫秒
    destroyAllWindows();//关闭窗口
    return 0;
}

2.两个解决方案不同的是
2.1测试(cs)解决方案的opencv配置是在解决方案文件目录下的

img


另一个我配置的是在盘目录下的,但是!我把另一个解决方案配置按照cs复制了一遍(在目录下复制了opencv库以及配置路径)

img

img

结果报错了,无论我怎么改又或者新建解决方案复制cs的步骤,结果都无法重现,都会报错link2019
甚至,我新建方案配置cs的opencv库目录都无法重现结果
PS.
重建新方案中唯一没出现当初cs结果的是我在在使用最后一篇代码时

img

img


也就是我新建的解决方案不用完全配置d.lib的具体路径就能运行,这是新解决方案和cs唯一的差别

我想要达到的结果

所以,这个问题应该怎么解决