Add Python files and update installation script

pull/156/merge
Dakota Benjamin 2015-08-20 19:16:25 +00:00
rodzic c6932c459d
commit 3bd80dcab5
14 zmienionych plików z 1415 dodań i 58 usunięć

2
.gitignore vendored
Wyświetl plik

@ -8,4 +8,6 @@ odm_texturing-build/
*.user
cmvs.tar.gz
parallel.tar.bz2
LAStools.zip
pcl.tar.gz
*.pyc

Wyświetl plik

@ -41,6 +41,7 @@ echo " - script started - `date`"
GRACLUS_PATH="$TOOLS_SRC_PATH/graclus"
PCL_PATH="$TOOLS_SRC_PATH/pcl"
LASTOOLS_PATH="$TOOLS_SRC_PATH/lastools"
ODM_MESHING_PATH="$TOOLS_SRC_PATH/odm_meshing"
ODM_TEXTURING_PATH="$TOOLS_SRC_PATH/odm_texturing"
ODM_ORTHOPHOTO_PATH="$TOOLS_SRC_PATH/odm_orthophoto"
@ -120,6 +121,8 @@ sudo apt-get install --assume-yes --install-recommends \
libzip-dev \
libswitch-perl libjson-perl \
libcv-dev libcvaux-dev libopencv-dev \
gdal-bin \
exiv2 \
> "$TOOLS_LOG_PATH/apt-get_install.log" 2>&1
else
sudo apt-get install --assume-yes --install-recommends \
@ -133,6 +136,8 @@ sudo apt-get install --assume-yes --install-recommends \
libzip-dev \
libswitch-perl \
libcv-dev libcvaux-dev libopencv-dev \
gdal-bin \
exiv2 \
> "$TOOLS_LOG_PATH/apt-get_install.log" 2>&1
fi
@ -167,6 +172,7 @@ vlfeat.tar.gz http://www.vlfeat.org/download/vlfeat-0.9.13-bin.tar.gz
cmvs.tar.gz http://www.di.ens.fr/cmvs/cmvs-fix2.tar.gz
graclus.tar.gz http://smathermather.github.io/BundlerTools/patched_files/src/graclus/graclus1.2.tar.gz
pcl.tar.gz https://github.com/PointCloudLibrary/pcl/archive/pcl-1.7.2.tar.gz
LAStools.zip http://lastools.org/download/LAStools.zip
EOF
echo " < done - `date`"
@ -195,6 +201,8 @@ mv -f parallel-20141022 "$PARALLEL_PATH"
mv -f PoissonRecon "$PSR_PATH"
mv -f cmvs "$CMVS_PATH"
mv -f pcl-pcl-1.7.2 "$PCL_PATH"
mv -f LAStools "$LASTOOLS_PATH"
echo " < done - `date`"
@ -308,6 +316,23 @@ echo " > vlfeat"
echo " < done - `date`"
echo
echo " > LAStools"
cd "$LASTOOLS_PATH"
echo " - installing LAStools"
make > "$TOOLS_LOG_PATH/lastools_1_build.log" 2>&1
if [ "$ARCH" = "i686" ]; then
cp -f "$LASTOOLS_PATH/bin/txt2las" "$TOOLS_BIN_PATH/txt2las"
fi
if [ "$ARCH" = "x86_64" ]; then
cp -f "$LASTOOLS_PATH/bin/txt2las" "$TOOLS_BIN_PATH/txt2las"
fi
echo " < done - `date`"
echo
echo " > cmvs/pmvs"
cd "$CMVS_PATH/program/main"

119
knnMatch_exif.py 100755
Wyświetl plik

@ -0,0 +1,119 @@
import os
import math
import subprocess
# Purpose:
# Preselect camera pairs for meature matching based by using GPS exif data.
def preselect_pairs(utm_extractor_path, image_list, k_distance, use_knn_mode = True, verbose = False):
# Parameterss:
# utm_extractor_path: Path to the odm utm_extraction program that parses exif data.
# images_path: Path to the folder containing the images.
# k_distance: Nearest neighbor count in case of use_knn_mode = True, otherwise
# the minimum distance between cameras to be matched.
# use_knn_mode: True if knn mode is used to preselect matches, False for distance thresholding.
# Temporary files
image_list_file = 'image_list_tmp.txt'
utm_coord_file = 'utm_coord_tmp.txt'
# Parse the list of files with successfullt detectd points.
image_folder = ""
filenames = []
with open(image_list, 'r') as keypoint_file:
first_line = keypoint_file.readline()
image_folder = first_line[:first_line.rfind("/")]
keypoint_file.seek(0)
for line in keypoint_file:
filename = line[line.rfind("/")+1:line.rfind(".")]
filename += ".jpg"
filenames.append(filename)
data = open(image_list_file, "w")
for filename in filenames:
data.write("%s\n" % filename)
data.close()
# Define call parameters for calling the odm_extract_utm module
utm_cmd = ''
if verbose:
utm_cmd = [utm_extractor_path, '-verbose', '-imagesPath', image_folder, \
'-imageListFile', image_list_file, '-outputCoordFile', utm_coord_file]
else:
utm_cmd = [utm_extractor_path, '-imagesPath', image_folder, '-imageListFile', \
image_list_file, '-outputCoordFile', utm_coord_file]
# Perform UTM extraction
utm_process = subprocess.Popen(utm_cmd, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
output, err = utm_process.communicate()
# Check return code
if utm_process.returncode != 0:
print "Error when performing utm_extraction, dumping log file:"
print output
os.remove(image_list_file)
return []
# Parse odm_extract_utm output
coords = []
with open('utm_coord_tmp.txt', 'r') as coord_file:
# Skip header lines
next(coord_file)
next(coord_file)
for line in coord_file:
first_space = line.find(' ')
second_space = first_space + line[first_space+1:].find(' ')
xCoord = float(line[0: first_space])
yCoord = float(line[first_space+1: second_space+1])
coords.append([xCoord, yCoord])
# Calculate distances between camera pairs
distances = []
for xo,yo in coords:
distances.append([])
for xi, yi in coords:
current_image = len(distances)
xDist = xo-xi
yDist = yo-yi
distance = math.sqrt(xDist*xDist + yDist*yDist)
current_image = len(distances[-1])
distances[-1].append([current_image, distance, False])
distances[-1].sort(key=lambda tup: tup[1])
# Select matched pairs and make there are no doubles
matched_pairs = []
if use_knn_mode:
# Make sure that image count > k
if len(coords) <= k_distance:
print "Warning, k >= image count, the result will be equivalent to exhaustive matching"
k_distance = len(coords)-1
for outer_index, sorted_list in enumerate(distances):
# Skip first element as distance will always be zero
for sorted_index in xrange(1, k_distance+1):
image_index, distance, dummy = distances[outer_index][sorted_index]
is_added = distances[outer_index][image_index][2]
if not is_added:
matched_pairs.append([outer_index, image_index])
distances[outer_index][image_index][2] = True
distances[image_index][outer_index][2] = True
else: # Distance mode
for outer_index, sorted_list in enumerate(distances):
# Skip first element as distance will always be zero
for image_index, distance, dummy in sorted_list:
if outer_index == image_index:
continue
if distance > k_distance:
break
is_added = distances[outer_index][image_index][2]
if not is_added:
matched_pairs.append([outer_index, image_index])
distances[outer_index][image_index][2] = True
distances[image_index][outer_index][2] = True
# Remove temporary files
os.remove(image_list_file)
os.remove(utm_coord_file)
return matched_pairs

Wyświetl plik

@ -5,5 +5,5 @@
int main (int argc, char **argv)
{
UtmExtractor utmExtractor;
utmExtractor.run(argc, argv);
return utmExtractor.run(argc, argv);
}

Wyświetl plik

@ -64,7 +64,7 @@ class OnMat3
public:
OnMat3(Vec3 r1, Vec3 r2, Vec3 r3);
OnMat3(const OnMat3 &o);
Vec3 r1_; /**< The first row of the matrix. **/
Vec3 r2_; /**< The second row of the matrix. **/
Vec3 r3_; /**< The third row of the matrix. **/

Wyświetl plik

@ -218,11 +218,15 @@ std::ostream& operator<<(std::ostream &os, const GeorefCamera &cam)
Georef::Georef() : log_(false)
{
georeferencePointCloud_ = false;
useGCP_ = false;
bundleFilename_ = "";
coordFilename_ = "";
inputCoordFilename_ = "";
outputCoordFilename_ = "";
inputObjFilename_ = "";
outputObjFilename_ = "";
exportCoordinateFile_ = false;
exportGeorefSystem_ = false;
}
Georef::~Georef()
@ -267,10 +271,13 @@ int Georef::run(int argc, char *argv[])
void Georef::parseArguments(int argc, char *argv[])
{
bool outputSpecified = false;
bool outputPointCloudSpecified = false;
bool imageListSpecified = false;
bool gcpFileSpecified = false;
bool imageLocation = false;
bool bundleResized = false;
bool outputCoordSpecified = false;
bool inputCoordSpecified = false;
logFile_ = std::string(argv[0]) + "_log.txt";
log_ << logFile_ << "\n";
@ -326,15 +333,28 @@ void Georef::parseArguments(int argc, char *argv[])
bundleFilename_ = std::string(argv[argIndex]);
log_ << "Reading cameras from: " << bundleFilename_ << "\n";
}
else if(argument == "-coordFile" && argIndex < argc)
else if(argument == "-inputCoordFile" && argIndex < argc)
{
argIndex++;
if (argIndex >= argc)
{
throw GeorefException("Argument '" + argument + "' expects 1 more input following it, but no more inputs were provided.");
}
coordFilename_ = std::string(argv[argIndex]);
log_ << "Reading cameras georeferenced positions from: " << coordFilename_ << "\n";
inputCoordFilename_ = std::string(argv[argIndex]);
log_ << "Reading cameras gps exif positions from: " << inputCoordFilename_ << "\n";
inputCoordSpecified = true;
}
else if(argument == "-outputCoordFile" && argIndex < argc)
{
argIndex++;
if (argIndex >= argc)
{
throw GeorefException("Argument '" + argument + "' expects 1 more input following it, but no more inputs were provided.");
}
outputCoordFilename_ = std::string(argv[argIndex]);
log_ << "Exporting cameras georeferenced gps positions to: " << outputCoordFilename_ << "\n";
exportCoordinateFile_ = true;
outputCoordSpecified = true;
}
else if(argument == "-inputFile" && argIndex < argc)
{
@ -346,6 +366,17 @@ void Georef::parseArguments(int argc, char *argv[])
inputObjFilename_ = std::string(argv[argIndex]);
log_ << "Reading textured mesh from: " << inputObjFilename_ << "\n";
}
else if(argument == "-inputPointCloudFile" && argIndex < argc)
{
argIndex++;
if (argIndex >= argc)
{
throw GeorefException("Argument '" + argument + "' expects 1 more input following it, but no more inputs were provided.");
}
inputPointCloudFilename_ = std::string(argv[argIndex]);
log_ << "Reading point cloud from: " << inputPointCloudFilename_ << "\n";
georeferencePointCloud_ = true;
}
else if(argument == "-gcpFile" && argIndex < argc)
{
argIndex++;
@ -379,6 +410,17 @@ void Georef::parseArguments(int argc, char *argv[])
log_ << "Images location is set to: " << imagesLocation_ << "\n";
imageLocation = true;
}
else if(argument == "-georefFileOutputPath" && argIndex < argc)
{
argIndex++;
if (argIndex >= argc)
{
throw GeorefException("Argument '" + argument + "' expects 1 more input following it, but no more inputs were provided.");
}
georefFilename_ = std::string(argv[argIndex]);
log_ << "Georef file output path is set to: " << georefFilename_ << "\n";
exportGeorefSystem_ = true;
}
else if(argument == "-bundleResizedTo" && argIndex < argc)
{
argIndex++;
@ -406,6 +448,17 @@ void Georef::parseArguments(int argc, char *argv[])
log_ << "Writing output to: " << outputObjFilename_ << "\n";
outputSpecified = true;
}
else if(argument == "-outputPointCloudFile" && argIndex < argc)
{
argIndex++;
if (argIndex >= argc)
{
throw GeorefException("Argument '" + argument + "' expects 1 more input following it, but no more inputs were provided.");
}
outputPointCloudFilename_ = std::string(argv[argIndex]);
log_ << "Writing output to: " << outputPointCloudFilename_ << "\n";
outputPointCloudSpecified = true;
}
else
{
printHelp();
@ -413,6 +466,11 @@ void Georef::parseArguments(int argc, char *argv[])
}
}
if (inputCoordSpecified && outputCoordSpecified)
{
throw GeorefException("Both output and input coordfile specified, only one of those are accepted.");
}
if (imageListSpecified && gcpFileSpecified && imageLocation && bundleResized)
{
useGCP_ = true;
@ -423,6 +481,11 @@ void Georef::parseArguments(int argc, char *argv[])
log_ << "Missing input in order to use GCP for georeferencing. Using EXIF data instead.\n";
}
if(georeferencePointCloud_ && !outputPointCloudSpecified)
{
setDefaultPointCloudOutput();
}
if(!outputSpecified)
{
setDefaultOutput();
@ -455,12 +518,18 @@ void Georef::printHelp()
log_ << "The file needs to be on the following line format:\n";
log_ << "easting northing height pixelrow pixelcol imagename\n\n";
log_ << "\"-coordFile <path>\" (mandatory if using exif data)" << "\n";
log_ << "\"-inputCoordFile <path>\" (mandatory if using exif data)" << "\n";
log_ << "\"Input cameras geroreferenced coords file.\n\n";
log_ << "\"-outputCoordFile <path>\" (optional)" << "\n";
log_ << "\"Output cameras geroreferenced coords file.\n\n";
log_ << "\"-inputFile <path>\" (mandatory)" << "\n";
log_ << "\"Input obj file that must contain a textured mesh.\n\n";
log_ << "\"-inputPointCloudFile <path>\" (optional)" << "\n";
log_ << "\"Input ply file that must contain a point cloud.\n\n";
log_ << "\"-imagesListPath <path>\" (mandatory if using ground control points)\n";
log_ << "Path to the list containing the image names used in the bundle.out file.\n\n";
@ -472,6 +541,9 @@ void Georef::printHelp()
log_ << "\"-outputFile <path>\" (optional, default <inputFile>_geo)" << "\n";
log_ << "\"Output obj file that will contain the georeferenced texture mesh.\n\n";
log_ << "\"-outputPointCloudFile <path>\" (mandatory if georeferencing a point cloud)" << "\n";
log_ << "\"Output ply file that will contain the georeferenced point cloud.\n\n";
log_.setIsPrintingInCout(printInCoutPop);
}
@ -480,7 +552,7 @@ void Georef::setDefaultOutput()
{
if(inputObjFilename_.empty())
{
throw GeorefException("Tried to generate default ouptut file without having an input file.");
throw GeorefException("Tried to generate default output file without having an input file.");
}
std::string tmp = inputObjFilename_;
@ -497,6 +569,27 @@ void Georef::setDefaultOutput()
log_ << "Writing output to: " << outputObjFilename_ << "\n";
}
void Georef::setDefaultPointCloudOutput()
{
if(inputPointCloudFilename_.empty())
{
throw GeorefException("Tried to generate default point cloud ouptut file without having an input file.");
}
std::string tmp = inputPointCloudFilename_;
size_t findPos = tmp.find_last_of(".");
if(std::string::npos == findPos)
{
throw GeorefException("Tried to generate default ouptut file, could not find .ply in the input file:\n\'"+inputPointCloudFilename_+"\'");
}
tmp = tmp.substr(0, findPos);
outputPointCloudFilename_ = tmp + "_geo.ply";
log_ << "Writing output to: " << outputPointCloudFilename_ << "\n";
}
void Georef::createGeoreferencedModel()
{
if (useGCP_)
@ -535,7 +628,7 @@ void Georef::readGCPs()
std::ifstream imageListStream(imagesListPath_.c_str());
if (!imageListStream.good())
{
throw GeorefException("Failed opening " + imagesListPath_ + " for reading.\n");
throw GeorefException("Failed opening image path " + imagesListPath_ + " for reading.\n");
}
for (size_t i=0; i<cameras_.size(); ++i)
@ -551,7 +644,7 @@ void Georef::readGCPs()
std::ifstream gcpStream(gcpFilename_.c_str());
if (!gcpStream.good())
{
throw GeorefException("Failed opening " + gcpFilename_ + " for reading.\n");
throw GeorefException("Failed opening gcp file " + gcpFilename_ + " for reading.\n");
}
std::string gcpString;
@ -820,7 +913,6 @@ void Georef::performGeoreferencingWithGCP()
// Update the mesh.
pcl::toPCLPointCloud2 (*meshCloud, mesh.cloud);
// Iterate over each part of the mesh (one per material), to make texture file paths relative the .mtl file.
for(size_t t = 0; t < mesh.tex_materials.size(); ++t)
{
@ -844,7 +936,53 @@ void Georef::performGeoreferencingWithGCP()
log_ << "Successfully saved model.\n";
}
printGeorefSystem();
if(georeferencePointCloud_)
{
//pcl::PointCloud2<pcl::PointNormal>::Ptr pointCloud;
pcl::PointCloud<pcl::PointXYZRGBNormal>::Ptr pointCloud(new pcl::PointCloud<pcl::PointXYZRGBNormal>());
if(pcl::io::loadPLYFile<pcl::PointXYZRGBNormal> (inputPointCloudFilename_.c_str(), *pointCloud.get()) == -1) {
throw GeorefException("Error when reading point cloud:\n" + inputPointCloudFilename_ + "\n");
}
else
{
log_ << "Successfully loaded " << pointCloud->size() << " points with corresponding normals from file.\n";
}
log_ << '\n';
log_ << "Applying transform to point cloud...\n";
pcl::transformPointCloud(*pointCloud, *pointCloud, transform);
log_ << ".. point cloud transformed.\n";
pcl::PLYWriter plyWriter;
log_ << '\n';
log_ << "Saving point cloud file to \'" << outputPointCloudFilename_ << "\'...\n";
//pcl::io::savePLYFileASCII(outputPointCloudFilename_.c_str(), *pointCloud.get());
plyWriter.write(outputPointCloudFilename_.c_str(), *pointCloud.get(), false, false);
log_ << ".. point cloud file saved.\n";
}
if(exportCoordinateFile_)
{
log_ << '\n';
log_ << "Saving georeferenced camera positions to ";
log_ << outputCoordFilename_;
log_<< "\n";
std::ofstream coordStream(outputCoordFilename_.c_str());
coordStream << georefSystem_.system_ <<std::endl;
coordStream << static_cast<int>(georefSystem_.eastingOffset_) << " " << static_cast<int>(georefSystem_.northingOffset_) << std::endl;
for(size_t cameraIndex = 0; cameraIndex < cameras_.size(); ++cameraIndex)
{
Vec3 globalCameraPosition = (transFinal.transform_)*(cameras_[cameraIndex].getPos());
coordStream << globalCameraPosition.x_ << " " << globalCameraPosition.y_ << " " << globalCameraPosition.z_ << std::endl;
}
coordStream.close();
log_ << "...coordinate file saved.\n";
}
if(exportGeorefSystem_)
{
printGeorefSystem();
}
}
void Georef::createGeoreferencedModelFromGCPData()
@ -864,10 +1002,10 @@ void Georef::createGeoreferencedModelFromExifData()
readCameras();
// Read coords from coord file generated by extract_utm tool
std::ifstream coordStream(coordFilename_.c_str());
std::ifstream coordStream(inputCoordFilename_.c_str());
if (!coordStream.good())
{
throw GeorefException("Failed opening " + coordFilename_ + " for reading." + '\n');
throw GeorefException("Failed opening coordinate file " + inputCoordFilename_ + " for reading." + '\n');
}
std::string coordString;
@ -891,7 +1029,7 @@ void Georef::createGeoreferencedModelFromExifData()
{
if(nGeorefCameras >= cameras_.size())
{
throw GeorefException("Error, to many cameras in \'" + coordFilename_ + "\' coord file.\n");
throw GeorefException("Error, to many cameras in \'" + inputCoordFilename_ + "\' coord file.\n");
}
std::istringstream istr(coordString);
@ -903,7 +1041,7 @@ void Georef::createGeoreferencedModelFromExifData()
if(nGeorefCameras < cameras_.size())
{
throw GeorefException("Not enough cameras in \'" + coordFilename_ + "\' coord file.\n");
throw GeorefException("Not enough cameras in \'" + inputCoordFilename_ + "\' coord file.\n");
}
// The optimal camera triplet.
@ -938,7 +1076,6 @@ void Georef::createGeoreferencedModelFromExifData()
log_ << '\n';
log_ << "Reading mesh file...\n";
// The textureds mesh.e
pcl::TextureMesh mesh;
pcl::io::loadOBJFile(inputObjFilename_, mesh);
log_ << ".. mesh file read.\n";
@ -956,7 +1093,6 @@ void Georef::createGeoreferencedModelFromExifData()
// Update the mesh.
pcl::toPCLPointCloud2 (*meshCloud, mesh.cloud);
// Iterate over each part of the mesh (one per material), to make texture file paths relative the .mtl file.
for(size_t t = 0; t < mesh.tex_materials.size(); ++t)
{
@ -975,7 +1111,35 @@ void Georef::createGeoreferencedModelFromExifData()
saveOBJFile(outputObjFilename_, mesh, 8);
log_ << ".. mesh file saved.\n";
printGeorefSystem();
if(georeferencePointCloud_)
{
//pcl::PointCloud2<pcl::PointNormal>::Ptr pointCloud;
pcl::PointCloud<pcl::PointXYZRGBNormal>::Ptr pointCloud(new pcl::PointCloud<pcl::PointXYZRGBNormal>());
if(pcl::io::loadPLYFile<pcl::PointXYZRGBNormal> (inputPointCloudFilename_.c_str(), *pointCloud.get()) == -1) {
throw GeorefException("Error when reading point cloud:\n" + inputPointCloudFilename_ + "\n");
}
else
{
log_ << "Successfully loaded " << pointCloud->size() << " points with corresponding normals from file.\n";
}
log_ << '\n';
log_ << "Applying transform to point cloud...\n";
pcl::transformPointCloud(*pointCloud, *pointCloud, transform);
log_ << ".. point cloud transformed.\n";
pcl::PLYWriter plyWriter;
log_ << '\n';
log_ << "Saving point cloud file to \'" << outputPointCloudFilename_ << "\'...\n";
//pcl::io::savePLYFileASCII(outputPointCloudFilename_.c_str(), *pointCloud.get());
plyWriter.write(outputPointCloudFilename_.c_str(), *pointCloud.get(), false, false);
log_ << ".. point cloud file saved.\n";
}
if(exportGeorefSystem_)
{
printGeorefSystem();
}
}
void Georef::chooseBestGCPTriplet(size_t &gcp0, size_t &gcp1, size_t &gcp2)
@ -1073,12 +1237,12 @@ void Georef::printGeorefSystem()
throw GeorefException("Tried to generate default ouptut file, could not find .obj in the output file:\n\'"+outputObjFilename_+"\'");
}
tmp = tmp.substr(0, findPos);
//tmp = tmp.substr(0, findPos);
tmp = tmp + "_georef_system.txt";
//tmp = tmp + "_georef_system.txt";
log_ << '\n';
log_ << "Saving georeference system file to \'" << tmp << "\'...\n";
std::ofstream geoStream(tmp.c_str());
log_ << "Saving georeference system file to \'" << georefFilename_ << "\'...\n";
std::ofstream geoStream(georefFilename_.c_str());
geoStream << georefSystem_ << std::endl;
geoStream.close();
log_ << "... georeference system saved.\n";

Wyświetl plik

@ -144,6 +144,11 @@ private:
*/
void setDefaultOutput();
/*!
* \brief setDefaultPointCloudOutput Setup the output file name given the input file name.
*/
void setDefaultPointCloudOutput();
/*!
* \brief createGeoreferencedModel Makes the input file georeferenced and saves it to the output file.
*/
@ -199,25 +204,32 @@ private:
**/
void printGeorefSystem();
Logger log_; /**< Logging object. */
std::string logFile_; /**< The path to the output log file. */
Logger log_; /**< Logging object. */
std::string logFile_; /**< The path to the output log file. */
std::string bundleFilename_; /**< The path to the cameras bundle file. **/
std::string coordFilename_; /**< The path to the cameras georeference file. **/
std::string gcpFilename_; /**< The path to the GCP file **/
std::string imagesListPath_; /**< Path to the image list. **/
std::string imagesLocation_; /**< The folder containing the images in the image list. **/
std::string inputObjFilename_; /**< The path to the input mesh obj file. **/
std::string outputObjFilename_; /**< The path to the output mesh obj file. **/
std::string bundleFilename_; /**< The path to the cameras bundle file. **/
std::string inputCoordFilename_; /**< The path to the cameras exif gps positions file. **/
std::string outputCoordFilename_; /**< The path to the cameras georeferenced gps positions file. **/
std::string gcpFilename_; /**< The path to the GCP file **/
std::string imagesListPath_; /**< Path to the image list. **/
std::string imagesLocation_; /**< The folder containing the images in the image list. **/
std::string inputObjFilename_; /**< The path to the input mesh obj file. **/
std::string outputObjFilename_; /**< The path to the output mesh obj file. **/
std::string inputPointCloudFilename_; /**< The path to the input point cloud file. **/
std::string outputPointCloudFilename_; /**< The path to the output point cloud file. **/
std::string georefFilename_; /**< The path to the output offset file. **/
bool useGCP_; /**< Check if GCP-file is present and use this to georeference the model. **/
double bundleResizedTo_; /**< The size used in the previous steps to calculate the camera focal_length. */
bool georeferencePointCloud_;
bool exportCoordinateFile_;
bool exportGeorefSystem_;
bool useGCP_; /**< Check if GCP-file is present and use this to georeference the model. **/
double bundleResizedTo_; /**< The size used in the previous steps to calculate the camera focal_length. */
std::vector<GeorefCamera> cameras_; /**< A vector of all cameras. **/
std::vector<GeorefGCP> gcps_; /**< A vector of all GCPs. **/
std::vector<std::string> imageList_; /**< A vector containing the names of the corresponding cameras. **/
std::vector<GeorefCamera> cameras_; /**< A vector of all cameras. **/
std::vector<GeorefGCP> gcps_; /**< A vector of all GCPs. **/
std::vector<std::string> imageList_; /**< A vector containing the names of the corresponding cameras. **/
GeorefSystem georefSystem_; /**< Contains the georeference system. **/
GeorefSystem georefSystem_; /**< Contains the georeference system. **/
};
/*!

0
odm_orthophoto/CMakeLists.txt 100755 → 100644
Wyświetl plik

0
odm_orthophoto/src/Logger.cpp 100755 → 100644
Wyświetl plik

0
odm_orthophoto/src/Logger.hpp 100755 → 100644
Wyświetl plik

Wyświetl plik

@ -1,6 +1,7 @@
// C++
#include <math.h>
#include <sstream>
#include <fstream>
// This
#include "OdmOrthoPhoto.hpp"
@ -44,6 +45,7 @@ OdmOrthoPhoto::OdmOrthoPhoto()
inputGeoRefFile_ = "";
outputFile_ = "ortho.jpg";
logFile_ = "log.txt";
outputCornerFile_ = "";
resolution_ = 0.0f;
@ -229,6 +231,16 @@ void OdmOrthoPhoto::parseArguments(int argc, char *argv[])
outputFile_ = std::string(argv[argIndex]);
log_ << "Writing output to: " << outputFile_ << "\n";
}
else if(argument == "-outputCornerFile")
{
argIndex++;
if (argIndex >= argc)
{
throw OdmOrthoPhotoException("Argument '" + argument + "' expects 1 more input following it, but no more inputs were provided.");
}
outputCornerFile_ = std::string(argv[argIndex]);
log_ << "Writing corners to: " << outputCornerFile_ << "\n";
}
else
{
printHelp();
@ -258,12 +270,15 @@ void OdmOrthoPhoto::printHelp()
log_ << "\"-inputFile <path>\" (mandatory)\n";
log_ << "\"Input obj file that must contain a textured mesh.\n\n";
log_ << "\"-inputGeoRefFile <path>\" (optional, if specified boundary points are assumed to be givan as world coordinates. If not specified, the boundary points are assumed to be local coordinates)\n";
log_ << "\"-inputGeoRefFile <path>\" (optional, if specified boundary points are assumed to be given as world coordinates. If not specified, the boundary points are assumed to be local coordinates)\n";
log_ << "\"Input geograpical reference system file that describes the world position of the model's origin.\n\n";
log_ << "\"-outputFile <path>\" (optional, default: ortho.jpg)\n";
log_ << "\"Target file in which the orthophoto is saved.\n\n";
log_ << "\"-outputCornerFile <path>\" (optional)\n";
log_ << "\"Target text file for boundary corner points, written as \"xmin ymin xmax ymax\".\n\n";
log_ << "\"-resolution <pixels/m>\" (mandatory)\n";
log_ << "\"The number of pixels used per meter.\n\n";
@ -364,7 +379,7 @@ void OdmOrthoPhoto::createOrthoPhoto()
}
// Init ortho photo
photo_ = cv::Mat::zeros(rowRes, colRes, CV_8UC3) + cv::Scalar(255, 255, 255);
photo_ = cv::Mat::zeros(rowRes, colRes, CV_8UC4) + cv::Scalar(255, 255, 255, 0);
depth_ = cv::Mat::zeros(rowRes, colRes, CV_32F) - std::numeric_limits<float>::infinity();
// Contains the vertices of the mesh.
@ -431,6 +446,21 @@ void OdmOrthoPhoto::createOrthoPhoto()
log_ << '\n';
log_ << "Writing ortho photo to " << outputFile_ << "\n";
cv::imwrite(outputFile_, photo_);
if (!outputCornerFile_.empty())
{
log_ << "Writing corner coordinates to " << outputCornerFile_ << "\n";
std::ofstream cornerStream(outputCornerFile_.c_str());
if (!cornerStream.is_open())
{
throw OdmOrthoPhotoException("Failed opening output corner file " + outputCornerFile_ + ".");
}
cornerStream.setf(std::ios::scientific, std::ios::floatfield);
cornerStream.precision(17);
cornerStream << xMin << " " << yMin << " " << xMax << " " << yMax;
cornerStream.close();
}
log_ << "Orthophoto generation done.\n";
}
@ -443,34 +473,34 @@ void OdmOrthoPhoto::adjustBoundsForGeoRef()
// The system name
std::string system;
// The false easting and northing
int falseEasting, falseNorthing;
// The east and north offsets
int eastOffset, northOffset;
// Parse file
std::getline(geoRefStream, system);
if(!(geoRefStream >> falseEasting))
if(!(geoRefStream >> eastOffset))
{
throw OdmOrthoPhotoException("Could not extract geographical reference system from \n" + inputGeoRefFile_ + "\nCould not extract false easting.");
throw OdmOrthoPhotoException("Could not extract geographical reference system from \n" + inputGeoRefFile_ + "\nCould not extract east offset.");
}
if(!(geoRefStream >> falseNorthing))
if(!(geoRefStream >> northOffset))
{
throw OdmOrthoPhotoException("Could not extract geographical reference system from \n" + inputGeoRefFile_ + "\nCould not extract false northing.");
throw OdmOrthoPhotoException("Could not extract geographical reference system from \n" + inputGeoRefFile_ + "\nCould not extract north offset.");
}
log_ << "Georeference system\n";
log_ << "Georeference system:\n";
log_ << system << "\n";
log_ << "False easting " << falseEasting << "\n";
log_ << "False northing " << falseNorthing << "\n";
log_ << "East offset: " << eastOffset << "\n";
log_ << "North offset: " << northOffset << "\n";
// Adjust boundary points.
boundaryPoint1_[0] = static_cast<float>(worldPoint1_.eastInteger_ - falseEasting) + worldPoint1_.eastFractional_;
boundaryPoint1_[1] = static_cast<float>(worldPoint1_.northInteger_ - falseNorthing) + worldPoint1_.northFractional_;
boundaryPoint2_[0] = static_cast<float>(worldPoint2_.eastInteger_ - falseEasting) + worldPoint2_.eastFractional_;
boundaryPoint2_[1] = static_cast<float>(worldPoint2_.northInteger_ - falseNorthing) + worldPoint2_.northFractional_;
boundaryPoint3_[0] = static_cast<float>(worldPoint3_.eastInteger_ - falseEasting) + worldPoint3_.eastFractional_;
boundaryPoint3_[1] = static_cast<float>(worldPoint3_.northInteger_ - falseNorthing) + worldPoint3_.northFractional_;
boundaryPoint4_[0] = static_cast<float>(worldPoint4_.eastInteger_ - falseEasting) + worldPoint4_.eastFractional_;
boundaryPoint4_[1] = static_cast<float>(worldPoint4_.northInteger_ - falseNorthing) + worldPoint4_.northFractional_;
boundaryPoint1_[0] = static_cast<float>(worldPoint1_.eastInteger_ - eastOffset) + worldPoint1_.eastFractional_;
boundaryPoint1_[1] = static_cast<float>(worldPoint1_.northInteger_ - northOffset) + worldPoint1_.northFractional_;
boundaryPoint2_[0] = static_cast<float>(worldPoint2_.eastInteger_ - eastOffset) + worldPoint2_.eastFractional_;
boundaryPoint2_[1] = static_cast<float>(worldPoint2_.northInteger_ - northOffset) + worldPoint2_.northFractional_;
boundaryPoint3_[0] = static_cast<float>(worldPoint3_.eastInteger_ - eastOffset) + worldPoint3_.eastFractional_;
boundaryPoint3_[1] = static_cast<float>(worldPoint3_.northInteger_ - northOffset) + worldPoint3_.northFractional_;
boundaryPoint4_[0] = static_cast<float>(worldPoint4_.eastInteger_ - eastOffset) + worldPoint4_.eastFractional_;
boundaryPoint4_[1] = static_cast<float>(worldPoint4_.northInteger_ - northOffset) + worldPoint4_.northFractional_;
log_ << "Local boundary points:\n";
log_ << "Point 1: " << boundaryPoint1_[0] << " " << boundaryPoint1_[1] << "\n";
@ -908,7 +938,7 @@ void OdmOrthoPhoto::renderPixel(int row, int col, float s, float t, const cv::Ma
b += static_cast<float>(bl[0]) * dr * dt;
b += static_cast<float>(br[0]) * dl * dt;
photo_.at<cv::Vec3b>(row,col) = cv::Vec3b(static_cast<unsigned char>(b), static_cast<unsigned char>(g), static_cast<unsigned char>(r));
photo_.at<cv::Vec4b>(row,col) = cv::Vec4b(static_cast<unsigned char>(b), static_cast<unsigned char>(g), static_cast<unsigned char>(r), 255);
}
void OdmOrthoPhoto::getBarycentricCoordiantes(pcl::PointXYZ v1, pcl::PointXYZ v2, pcl::PointXYZ v3, float x, float y, float &l1, float &l2, float &l3) const

Wyświetl plik

@ -177,6 +177,7 @@ private:
std::string inputFile_; /**< Path to the textured mesh as an obj-file. */
std::string inputGeoRefFile_; /**< Path to the georeference system file. */
std::string outputFile_; /**< Path to the destination file. */
std::string outputCornerFile_; /**< Path to the output corner file. */
std::string logFile_; /**< Path to the log file. */
float resolution_; /**< The number of pixels per meter in the ortho photo. */

0
odm_orthophoto/src/main.cpp 100755 → 100644
Wyświetl plik

1004
run.py 100755

Plik diff jest za duży Load Diff