first
|
@ -0,0 +1,99 @@
|
|||
/**
|
||||
* @file widget_pose.cpp
|
||||
* @brief Setting pose of a widget
|
||||
* @author Ozan Cagri Tonkal
|
||||
*/
|
||||
|
||||
#include <opencv2/viz.hpp>
|
||||
#include <opencv2/calib3d.hpp>
|
||||
#include <iostream>
|
||||
|
||||
using namespace cv;
|
||||
using namespace std;
|
||||
|
||||
/**
|
||||
* @function help
|
||||
* @brief Display instructions to use this tutorial program
|
||||
*/
|
||||
static void help()
|
||||
{
|
||||
cout
|
||||
<< "--------------------------------------------------------------------------" << endl
|
||||
<< "This program shows how to visualize a cube rotated around (1,1,1) and shifted "
|
||||
<< "using Rodrigues vector." << endl
|
||||
<< "Usage:" << endl
|
||||
<< "./widget_pose" << endl
|
||||
<< endl;
|
||||
}
|
||||
|
||||
/**
|
||||
* @function main
|
||||
*/
|
||||
int main()
|
||||
{
|
||||
help();
|
||||
|
||||
/// Create a window
|
||||
viz::Viz3d myWindow("Coordinate Frame");
|
||||
|
||||
/// Add coordinate axes
|
||||
myWindow.showWidget("Coordinate Widget", viz::WCoordinateSystem());
|
||||
|
||||
/// Add line to represent (1,1,1) axis
|
||||
viz::WLine axis(Point3f(-1.0f,-1.0f,-1.0f), Point3f(1.0f,1.0f,1.0f));
|
||||
axis.setRenderingProperty(viz::LINE_WIDTH, 4.0);
|
||||
myWindow.showWidget("Line Widget", axis);
|
||||
|
||||
/// Construct a cube widget
|
||||
viz::WCube cube_widget(Point3f(0.5,0.5,0.0), Point3f(0.0,0.0,-0.5), true, viz::Color::blue());
|
||||
cube_widget.setRenderingProperty(viz::LINE_WIDTH, 4.0);
|
||||
myWindow.showWidget("Cube Widget", cube_widget);
|
||||
|
||||
/// Rodrigues vector
|
||||
Mat rot_vec = Mat::zeros(1,3,CV_32F);
|
||||
float translation_phase = 0.0, translation = 0.0;
|
||||
|
||||
rot_vec.at<float>(0, 0) += (float)CV_PI * 0.01f;
|
||||
rot_vec.at<float>(0, 1) += (float)CV_PI * 0.01f;
|
||||
rot_vec.at<float>(0, 2) += (float)CV_PI * 0.01f;
|
||||
|
||||
/// Shift on (1,1,1)
|
||||
translation_phase += (float)CV_PI * 0.01f;
|
||||
translation = sin(translation_phase);
|
||||
|
||||
Mat rot_mat;
|
||||
Rodrigues(rot_vec, rot_mat);
|
||||
cout << "rot_mat = " << rot_mat << endl;
|
||||
/// Construct pose
|
||||
Affine3f pose(rot_mat, Vec3f(translation, translation, translation));
|
||||
Affine3f pose2(pose.matrix);
|
||||
cout << "pose = " << pose.matrix << endl;
|
||||
cout << "pose = " << pose2.matrix << endl;
|
||||
|
||||
|
||||
|
||||
while(!myWindow.wasStopped())
|
||||
{
|
||||
/* Rotation using rodrigues */
|
||||
/// Rotate around (1,1,1)
|
||||
rot_vec.at<float>(0,0) += (float)CV_PI * 0.01f;
|
||||
rot_vec.at<float>(0,1) += (float)CV_PI * 0.01f;
|
||||
rot_vec.at<float>(0,2) += (float)CV_PI * 0.01f;
|
||||
|
||||
/// Shift on (1,1,1)
|
||||
translation_phase += (float)CV_PI * 0.01f;
|
||||
translation = sin(translation_phase);
|
||||
|
||||
Mat rot_mat1;
|
||||
Rodrigues(rot_vec, rot_mat1);
|
||||
|
||||
/// Construct pose
|
||||
Affine3f pose1(rot_mat1, Vec3f(translation, translation, translation));
|
||||
|
||||
myWindow.setWidgetPose("Cube Widget", pose1);
|
||||
|
||||
myWindow.spinOnce(1, true);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,530 @@
|
|||
/*M///////////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
|
||||
//
|
||||
// By downloading, copying, installing or using the software you agree to this license.
|
||||
// If you do not agree to this license, do not download, install,
|
||||
// copy or use the software.
|
||||
//
|
||||
//
|
||||
// License Agreement
|
||||
// For Open Source Computer Vision Library
|
||||
//
|
||||
// Copyright (C) 2013, OpenCV Foundation, all rights reserved.
|
||||
// Third party copyrights are property of their respective owners.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without modification,
|
||||
// are permitted provided that the following conditions are met:
|
||||
//
|
||||
// * Redistribution's of source code must retain the above copyright notice,
|
||||
// this list of conditions and the following disclaimer.
|
||||
//
|
||||
// * Redistribution's in binary form must reproduce the above copyright notice,
|
||||
// this list of conditions and the following disclaimer in the documentation
|
||||
// and/or other materials provided with the distribution.
|
||||
//
|
||||
// * The name of the copyright holders may not be used to endorse or promote products
|
||||
// derived from this software without specific prior written permission.
|
||||
//
|
||||
// This software is provided by the copyright holders and contributors "as is" and
|
||||
// any express or implied warranties, including, but not limited to, the implied
|
||||
// warranties of merchantability and fitness for a particular purpose are disclaimed.
|
||||
// In no event shall the Intel Corporation or contributors be liable for any direct,
|
||||
// indirect, incidental, special, exemplary, or consequential damages
|
||||
// (including, but not limited to, procurement of substitute goods or services;
|
||||
// loss of use, data, or profits; or business interruption) however caused
|
||||
// and on any theory of liability, whether in contract, strict liability,
|
||||
// or tort (including negligence or otherwise) arising in any way out of
|
||||
// the use of this software, even if advised of the possibility of such damage.
|
||||
//
|
||||
// Authors:
|
||||
// * Ozan Tonkal, ozantonkal@gmail.com
|
||||
// * Anatoly Baksheev, Itseez Inc. myname.mysurname <> mycompany.com
|
||||
//
|
||||
//M*/
|
||||
|
||||
#include "precomp.hpp"
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////
|
||||
/// Point Cloud Widget implementation
|
||||
|
||||
cv::viz::WCloud::WCloud(InputArray cloud, InputArray colors)
|
||||
{
|
||||
WCloud cloud_widget(cloud, colors, cv::noArray());
|
||||
*this = cloud_widget;
|
||||
}
|
||||
|
||||
cv::viz::WCloud::WCloud(InputArray cloud, const Color &color)
|
||||
{
|
||||
WCloud cloud_widget(cloud, Mat(cloud.size(), CV_8UC3, color));
|
||||
*this = cloud_widget;
|
||||
}
|
||||
|
||||
cv::viz::WCloud::WCloud(InputArray cloud, const Color &color, InputArray normals)
|
||||
{
|
||||
WCloud cloud_widget(cloud, Mat(cloud.size(), CV_8UC3, color), normals);
|
||||
*this = cloud_widget;
|
||||
}
|
||||
|
||||
cv::viz::WCloud::WCloud(cv::InputArray cloud, cv::InputArray colors, cv::InputArray normals)
|
||||
{
|
||||
CV_Assert(!cloud.empty() && !colors.empty());
|
||||
|
||||
vtkSmartPointer<vtkCloudMatSource> cloud_source = vtkSmartPointer<vtkCloudMatSource>::New();
|
||||
cloud_source->SetColorCloudNormals(cloud, colors, normals);
|
||||
cloud_source->Update();
|
||||
|
||||
vtkSmartPointer<vtkPolyDataMapper> mapper = vtkSmartPointer<vtkPolyDataMapper>::New();
|
||||
VtkUtils::SetInputData(mapper, cloud_source->GetOutput());
|
||||
mapper->SetScalarModeToUsePointData();
|
||||
#if VTK_MAJOR_VERSION < 8
|
||||
mapper->ImmediateModeRenderingOff();
|
||||
#endif
|
||||
mapper->SetScalarRange(0, 255);
|
||||
mapper->ScalarVisibilityOn();
|
||||
|
||||
vtkSmartPointer<vtkActor> actor = vtkSmartPointer<vtkActor>::New();
|
||||
actor->GetProperty()->SetInterpolationToFlat();
|
||||
actor->GetProperty()->BackfaceCullingOn();
|
||||
actor->SetMapper(mapper);
|
||||
|
||||
WidgetAccessor::setProp(*this, actor);
|
||||
}
|
||||
|
||||
template<> cv::viz::WCloud cv::viz::Widget::cast<cv::viz::WCloud>() const
|
||||
{
|
||||
Widget3D widget = this->cast<Widget3D>();
|
||||
return static_cast<WCloud&>(widget);
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////
|
||||
/// Painted Cloud Widget implementation
|
||||
|
||||
cv::viz::WPaintedCloud::WPaintedCloud(InputArray cloud)
|
||||
{
|
||||
vtkSmartPointer<vtkCloudMatSource> cloud_source = vtkSmartPointer<vtkCloudMatSource>::New();
|
||||
cloud_source->SetCloud(cloud);
|
||||
cloud_source->Update();
|
||||
|
||||
Vec6d bounds(cloud_source->GetOutput()->GetPoints()->GetBounds());
|
||||
|
||||
vtkSmartPointer<vtkElevationFilter> elevation = vtkSmartPointer<vtkElevationFilter>::New();
|
||||
elevation->SetInputConnection(cloud_source->GetOutputPort());
|
||||
elevation->SetLowPoint(bounds[0], bounds[2], bounds[4]);
|
||||
elevation->SetHighPoint(bounds[1], bounds[3], bounds[5]);
|
||||
elevation->SetScalarRange(0.0, 1.0);
|
||||
elevation->Update();
|
||||
|
||||
vtkSmartPointer<vtkPolyDataMapper> mapper = vtkSmartPointer<vtkPolyDataMapper>::New();
|
||||
VtkUtils::SetInputData(mapper, vtkPolyData::SafeDownCast(elevation->GetOutput()));
|
||||
#if VTK_MAJOR_VERSION < 8
|
||||
mapper->ImmediateModeRenderingOff();
|
||||
#endif
|
||||
mapper->ScalarVisibilityOn();
|
||||
mapper->SetColorModeToMapScalars();
|
||||
|
||||
vtkSmartPointer<vtkActor> actor = vtkSmartPointer<vtkActor>::New();
|
||||
actor->GetProperty()->SetInterpolationToFlat();
|
||||
actor->GetProperty()->BackfaceCullingOn();
|
||||
actor->SetMapper(mapper);
|
||||
|
||||
WidgetAccessor::setProp(*this, actor);
|
||||
}
|
||||
|
||||
cv::viz::WPaintedCloud::WPaintedCloud(InputArray cloud, const Point3d& p1, const Point3d& p2)
|
||||
{
|
||||
vtkSmartPointer<vtkCloudMatSource> cloud_source = vtkSmartPointer<vtkCloudMatSource>::New();
|
||||
cloud_source->SetCloud(cloud);
|
||||
|
||||
vtkSmartPointer<vtkElevationFilter> elevation = vtkSmartPointer<vtkElevationFilter>::New();
|
||||
elevation->SetInputConnection(cloud_source->GetOutputPort());
|
||||
elevation->SetLowPoint(p1.x, p1.y, p1.z);
|
||||
elevation->SetHighPoint(p2.x, p2.y, p2.z);
|
||||
elevation->SetScalarRange(0.0, 1.0);
|
||||
elevation->Update();
|
||||
|
||||
vtkSmartPointer<vtkPolyDataMapper> mapper = vtkSmartPointer<vtkPolyDataMapper>::New();
|
||||
VtkUtils::SetInputData(mapper, vtkPolyData::SafeDownCast(elevation->GetOutput()));
|
||||
#if VTK_MAJOR_VERSION < 8
|
||||
mapper->ImmediateModeRenderingOff();
|
||||
#endif
|
||||
mapper->ScalarVisibilityOn();
|
||||
mapper->SetColorModeToMapScalars();
|
||||
|
||||
vtkSmartPointer<vtkActor> actor = vtkSmartPointer<vtkActor>::New();
|
||||
actor->GetProperty()->SetInterpolationToFlat();
|
||||
actor->GetProperty()->BackfaceCullingOn();
|
||||
actor->SetMapper(mapper);
|
||||
|
||||
WidgetAccessor::setProp(*this, actor);
|
||||
}
|
||||
|
||||
cv::viz::WPaintedCloud::WPaintedCloud(InputArray cloud, const Point3d& p1, const Point3d& p2, const Color& c1, const Color c2)
|
||||
{
|
||||
vtkSmartPointer<vtkCloudMatSource> cloud_source = vtkSmartPointer<vtkCloudMatSource>::New();
|
||||
cloud_source->SetCloud(cloud);
|
||||
|
||||
vtkSmartPointer<vtkElevationFilter> elevation = vtkSmartPointer<vtkElevationFilter>::New();
|
||||
elevation->SetInputConnection(cloud_source->GetOutputPort());
|
||||
elevation->SetLowPoint(p1.x, p1.y, p1.z);
|
||||
elevation->SetHighPoint(p2.x, p2.y, p2.z);
|
||||
elevation->SetScalarRange(0.0, 1.0);
|
||||
elevation->Update();
|
||||
|
||||
Color vc1 = vtkcolor(c1), vc2 = vtkcolor(c2);
|
||||
vtkSmartPointer<vtkColorTransferFunction> color_transfer = vtkSmartPointer<vtkColorTransferFunction>::New();
|
||||
color_transfer->SetColorSpaceToRGB();
|
||||
color_transfer->AddRGBPoint(0.0, vc1[0], vc1[1], vc1[2]);
|
||||
color_transfer->AddRGBPoint(1.0, vc2[0], vc2[1], vc2[2]);
|
||||
color_transfer->SetScaleToLinear();
|
||||
color_transfer->Build();
|
||||
|
||||
//if in future some need to replace color table with real scalars, then this can be done usine next calls:
|
||||
//vtkDataArray *float_scalars = vtkPolyData::SafeDownCast(elevation->GetOutput())->GetPointData()->GetArray("Elevation");
|
||||
//vtkSmartPointer<vtkPolyData> polydata = cloud_source->GetOutput();
|
||||
//polydata->GetPointData()->SetScalars(color_transfer->MapScalars(float_scalars, VTK_COLOR_MODE_DEFAULT, 0));
|
||||
|
||||
vtkSmartPointer<vtkPolyDataMapper> mapper = vtkSmartPointer<vtkPolyDataMapper>::New();
|
||||
VtkUtils::SetInputData(mapper, vtkPolyData::SafeDownCast(elevation->GetOutput()));
|
||||
#if VTK_MAJOR_VERSION < 8
|
||||
mapper->ImmediateModeRenderingOff();
|
||||
#endif
|
||||
mapper->ScalarVisibilityOn();
|
||||
mapper->SetColorModeToMapScalars();
|
||||
mapper->SetLookupTable(color_transfer);
|
||||
|
||||
vtkSmartPointer<vtkActor> actor = vtkSmartPointer<vtkActor>::New();
|
||||
actor->GetProperty()->SetInterpolationToFlat();
|
||||
actor->GetProperty()->BackfaceCullingOn();
|
||||
actor->SetMapper(mapper);
|
||||
|
||||
WidgetAccessor::setProp(*this, actor);
|
||||
}
|
||||
|
||||
template<> cv::viz::WPaintedCloud cv::viz::Widget::cast<cv::viz::WPaintedCloud>() const
|
||||
{
|
||||
Widget3D widget = this->cast<Widget3D>();
|
||||
return static_cast<WPaintedCloud&>(widget);
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////
|
||||
/// Cloud Collection Widget implementation
|
||||
|
||||
cv::viz::WCloudCollection::WCloudCollection()
|
||||
{
|
||||
vtkSmartPointer<vtkAppendPolyData> append_filter = vtkSmartPointer<vtkAppendPolyData>::New();
|
||||
|
||||
vtkSmartPointer<vtkPolyDataMapper> mapper = vtkSmartPointer<vtkPolyDataMapper>::New();
|
||||
mapper->SetInputConnection(append_filter->GetOutputPort());
|
||||
mapper->SetScalarModeToUsePointData();
|
||||
#if VTK_MAJOR_VERSION < 8
|
||||
mapper->ImmediateModeRenderingOff();
|
||||
#endif
|
||||
mapper->SetScalarRange(0, 255);
|
||||
mapper->ScalarVisibilityOn();
|
||||
|
||||
vtkSmartPointer<vtkLODActor> actor = vtkSmartPointer<vtkLODActor>::New();
|
||||
actor->SetNumberOfCloudPoints(1);
|
||||
actor->GetProperty()->SetInterpolationToFlat();
|
||||
actor->GetProperty()->BackfaceCullingOn();
|
||||
actor->SetMapper(mapper);
|
||||
|
||||
WidgetAccessor::setProp(*this, actor);
|
||||
}
|
||||
|
||||
void cv::viz::WCloudCollection::addCloud(InputArray cloud, InputArray colors, const Affine3d &pose)
|
||||
{
|
||||
vtkSmartPointer<vtkCloudMatSource> source = vtkSmartPointer<vtkCloudMatSource>::New();
|
||||
source->SetColorCloud(cloud, colors);
|
||||
|
||||
vtkSmartPointer<vtkPolyData> polydata = VtkUtils::TransformPolydata(source->GetOutputPort(), pose);
|
||||
|
||||
vtkSmartPointer<vtkLODActor> actor = vtkLODActor::SafeDownCast(WidgetAccessor::getProp(*this));
|
||||
CV_Assert("Correctness check." && actor);
|
||||
|
||||
vtkSmartPointer<vtkAlgorithm> producer = actor->GetMapper()->GetInputConnection(0, 0)->GetProducer();
|
||||
vtkSmartPointer<vtkAppendPolyData> append_filter = vtkAppendPolyData::SafeDownCast(producer);
|
||||
VtkUtils::AddInputData(append_filter, polydata);
|
||||
|
||||
actor->SetNumberOfCloudPoints(std::max<vtkIdType>(1, actor->GetNumberOfCloudPoints() + polydata->GetNumberOfPoints()/10));
|
||||
}
|
||||
|
||||
void cv::viz::WCloudCollection::addCloud(InputArray cloud, const Color &color, const Affine3d &pose)
|
||||
{
|
||||
addCloud(cloud, Mat(cloud.size(), CV_8UC3, color), pose);
|
||||
}
|
||||
|
||||
void cv::viz::WCloudCollection::finalize()
|
||||
{
|
||||
vtkSmartPointer<vtkLODActor> actor = vtkLODActor::SafeDownCast(WidgetAccessor::getProp(*this));
|
||||
CV_Assert("Incompatible widget type." && actor);
|
||||
|
||||
vtkSmartPointer<vtkPolyDataMapper> mapper = vtkPolyDataMapper::SafeDownCast(actor->GetMapper());
|
||||
CV_Assert("Need to add at least one cloud." && mapper);
|
||||
|
||||
vtkSmartPointer<vtkAlgorithm> producer = mapper->GetInputConnection(0, 0)->GetProducer();
|
||||
vtkSmartPointer<vtkAppendPolyData> append_filter = vtkAppendPolyData::SafeDownCast(producer);
|
||||
append_filter->Update();
|
||||
|
||||
vtkSmartPointer<vtkPolyData> polydata = append_filter->GetOutput();
|
||||
mapper->RemoveInputConnection(0, 0);
|
||||
VtkUtils::SetInputData(mapper, polydata);
|
||||
}
|
||||
|
||||
template<> cv::viz::WCloudCollection cv::viz::Widget::cast<cv::viz::WCloudCollection>() const
|
||||
{
|
||||
Widget3D widget = this->cast<Widget3D>();
|
||||
return static_cast<WCloudCollection&>(widget);
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////
|
||||
/// Cloud Normals Widget implementation
|
||||
|
||||
cv::viz::WCloudNormals::WCloudNormals(InputArray _cloud, InputArray _normals, int level, double scale, const Color &color)
|
||||
{
|
||||
Mat cloud = _cloud.getMat();
|
||||
Mat normals = _normals.getMat();
|
||||
|
||||
CV_Assert(cloud.type() == CV_32FC3 || cloud.type() == CV_64FC3 || cloud.type() == CV_32FC4 || cloud.type() == CV_64FC4);
|
||||
CV_Assert(cloud.size() == normals.size() && cloud.type() == normals.type());
|
||||
|
||||
int sqlevel = (int)std::sqrt((double)level);
|
||||
int ystep = (cloud.cols > 1 && cloud.rows > 1) ? sqlevel : 1;
|
||||
int xstep = (cloud.cols > 1 && cloud.rows > 1) ? sqlevel : level;
|
||||
|
||||
vtkSmartPointer<vtkPoints> points = vtkSmartPointer<vtkPoints>::New();
|
||||
points->SetDataType(cloud.depth() == CV_32F ? VTK_FLOAT : VTK_DOUBLE);
|
||||
|
||||
vtkSmartPointer<vtkCellArray> lines = vtkSmartPointer<vtkCellArray>::New();
|
||||
|
||||
int s_chs = cloud.channels();
|
||||
int n_chs = normals.channels();
|
||||
int total = 0;
|
||||
|
||||
for(int y = 0; y < cloud.rows; y += ystep)
|
||||
{
|
||||
if (cloud.depth() == CV_32F)
|
||||
{
|
||||
const float *srow = cloud.ptr<float>(y);
|
||||
const float *send = srow + cloud.cols * s_chs;
|
||||
const float *nrow = normals.ptr<float>(y);
|
||||
|
||||
for (; srow < send; srow += xstep * s_chs, nrow += xstep * n_chs)
|
||||
if (!isNan(srow) && !isNan(nrow))
|
||||
{
|
||||
Vec3f endp = Vec3f(srow) + Vec3f(nrow) * (float)scale;
|
||||
|
||||
points->InsertNextPoint(srow);
|
||||
points->InsertNextPoint(endp.val);
|
||||
|
||||
lines->InsertNextCell(2);
|
||||
lines->InsertCellPoint(total++);
|
||||
lines->InsertCellPoint(total++);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
const double *srow = cloud.ptr<double>(y);
|
||||
const double *send = srow + cloud.cols * s_chs;
|
||||
const double *nrow = normals.ptr<double>(y);
|
||||
|
||||
for (; srow < send; srow += xstep * s_chs, nrow += xstep * n_chs)
|
||||
if (!isNan(srow) && !isNan(nrow))
|
||||
{
|
||||
Vec3d endp = Vec3d(srow) + Vec3d(nrow) * (double)scale;
|
||||
|
||||
points->InsertNextPoint(srow);
|
||||
points->InsertNextPoint(endp.val);
|
||||
|
||||
lines->InsertNextCell(2);
|
||||
lines->InsertCellPoint(total++);
|
||||
lines->InsertCellPoint(total++);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
vtkSmartPointer<vtkPolyData> polydata = vtkSmartPointer<vtkPolyData>::New();
|
||||
polydata->SetPoints(points);
|
||||
polydata->SetLines(lines);
|
||||
VtkUtils::FillScalars(polydata, color);
|
||||
|
||||
vtkSmartPointer<vtkDataSetMapper> mapper = vtkSmartPointer<vtkDataSetMapper>::New();
|
||||
VtkUtils::SetInputData(mapper, polydata);
|
||||
|
||||
vtkSmartPointer<vtkActor> actor = vtkSmartPointer<vtkActor>::New();
|
||||
actor->SetMapper(mapper);
|
||||
|
||||
WidgetAccessor::setProp(*this, actor);
|
||||
}
|
||||
|
||||
template<> cv::viz::WCloudNormals cv::viz::Widget::cast<cv::viz::WCloudNormals>() const
|
||||
{
|
||||
Widget3D widget = this->cast<Widget3D>();
|
||||
return static_cast<WCloudNormals&>(widget);
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////
|
||||
/// Mesh Widget implementation
|
||||
|
||||
cv::viz::WMesh::WMesh(const Mesh &mesh)
|
||||
{
|
||||
CV_Assert(mesh.cloud.rows == 1 && mesh.polygons.type() == CV_32SC1);
|
||||
|
||||
vtkSmartPointer<vtkCloudMatSource> source = vtkSmartPointer<vtkCloudMatSource>::New();
|
||||
source->SetColorCloudNormalsTCoords(mesh.cloud, mesh.colors, mesh.normals, mesh.tcoords);
|
||||
source->Update();
|
||||
|
||||
Mat lookup_buffer(1, (int)mesh.cloud.total(), CV_32SC1);
|
||||
int *lookup = lookup_buffer.ptr<int>();
|
||||
for(int y = 0, index = 0; y < mesh.cloud.rows; ++y)
|
||||
{
|
||||
int s_chs = mesh.cloud.channels();
|
||||
|
||||
if (mesh.cloud.depth() == CV_32F)
|
||||
{
|
||||
const float* srow = mesh.cloud.ptr<float>(y);
|
||||
const float* send = srow + mesh.cloud.cols * s_chs;
|
||||
|
||||
for (; srow != send; srow += s_chs, ++lookup)
|
||||
if (!isNan(srow[0]) && !isNan(srow[1]) && !isNan(srow[2]))
|
||||
*lookup = index++;
|
||||
}
|
||||
|
||||
if (mesh.cloud.depth() == CV_64F)
|
||||
{
|
||||
const double* srow = mesh.cloud.ptr<double>(y);
|
||||
const double* send = srow + mesh.cloud.cols * s_chs;
|
||||
|
||||
for (; srow != send; srow += s_chs, ++lookup)
|
||||
if (!isNan(srow[0]) && !isNan(srow[1]) && !isNan(srow[2]))
|
||||
*lookup = index++;
|
||||
}
|
||||
}
|
||||
lookup = lookup_buffer.ptr<int>();
|
||||
|
||||
vtkSmartPointer<vtkPolyData> polydata = source->GetOutput();
|
||||
polydata->SetVerts(0);
|
||||
|
||||
const int * polygons = mesh.polygons.ptr<int>();
|
||||
vtkSmartPointer<vtkCellArray> cell_array = vtkSmartPointer<vtkCellArray>::New();
|
||||
|
||||
int idx = 0;
|
||||
size_t polygons_size = mesh.polygons.total();
|
||||
for (size_t i = 0; i < polygons_size; ++idx)
|
||||
{
|
||||
int n_points = polygons[i++];
|
||||
|
||||
cell_array->InsertNextCell(n_points);
|
||||
for (int j = 0; j < n_points; ++j, ++idx)
|
||||
cell_array->InsertCellPoint(lookup[polygons[i++]]);
|
||||
}
|
||||
cell_array->GetData()->SetNumberOfValues(idx);
|
||||
cell_array->Squeeze();
|
||||
polydata->SetStrips(cell_array);
|
||||
|
||||
vtkSmartPointer<vtkPolyDataMapper> mapper = vtkSmartPointer<vtkPolyDataMapper>::New();
|
||||
mapper->SetScalarModeToUsePointData();
|
||||
#if VTK_MAJOR_VERSION < 8
|
||||
mapper->ImmediateModeRenderingOff();
|
||||
#endif
|
||||
VtkUtils::SetInputData(mapper, polydata);
|
||||
|
||||
vtkSmartPointer<vtkActor> actor = vtkSmartPointer<vtkActor>::New();
|
||||
//actor->SetNumberOfCloudPoints(std::max(1, polydata->GetNumberOfPoints() / 10));
|
||||
actor->GetProperty()->SetRepresentationToSurface();
|
||||
actor->GetProperty()->BackfaceCullingOff(); // Backface culling is off for higher efficiency
|
||||
actor->GetProperty()->SetInterpolationToFlat();
|
||||
actor->GetProperty()->EdgeVisibilityOff();
|
||||
actor->GetProperty()->ShadingOff();
|
||||
actor->SetMapper(mapper);
|
||||
|
||||
if (!mesh.texture.empty())
|
||||
{
|
||||
vtkSmartPointer<vtkImageMatSource> image_source = vtkSmartPointer<vtkImageMatSource>::New();
|
||||
image_source->SetImage(mesh.texture);
|
||||
|
||||
vtkSmartPointer<vtkTexture> texture = vtkSmartPointer<vtkTexture>::New();
|
||||
texture->SetInputConnection(image_source->GetOutputPort());
|
||||
actor->SetTexture(texture);
|
||||
}
|
||||
|
||||
WidgetAccessor::setProp(*this, actor);
|
||||
}
|
||||
|
||||
cv::viz::WMesh::WMesh(InputArray cloud, InputArray polygons, InputArray colors, InputArray normals)
|
||||
{
|
||||
Mesh mesh;
|
||||
mesh.cloud = cloud.getMat();
|
||||
mesh.colors = colors.getMat();
|
||||
mesh.normals = normals.getMat();
|
||||
mesh.polygons = polygons.getMat();
|
||||
*this = WMesh(mesh);
|
||||
}
|
||||
|
||||
template<> CV_EXPORTS cv::viz::WMesh cv::viz::Widget::cast<cv::viz::WMesh>() const
|
||||
{
|
||||
Widget3D widget = this->cast<Widget3D>();
|
||||
return static_cast<WMesh&>(widget);
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////
|
||||
/// Widget Merger implementation
|
||||
|
||||
cv::viz::WWidgetMerger::WWidgetMerger()
|
||||
{
|
||||
vtkSmartPointer<vtkAppendPolyData> append_filter = vtkSmartPointer<vtkAppendPolyData>::New();
|
||||
|
||||
vtkSmartPointer<vtkPolyDataMapper> mapper = vtkSmartPointer<vtkPolyDataMapper>::New();
|
||||
mapper->SetInputConnection(append_filter->GetOutputPort());
|
||||
mapper->SetScalarModeToUsePointData();
|
||||
#if VTK_MAJOR_VERSION < 8
|
||||
mapper->ImmediateModeRenderingOff();
|
||||
#endif
|
||||
mapper->SetScalarRange(0, 255);
|
||||
mapper->ScalarVisibilityOn();
|
||||
|
||||
vtkSmartPointer<vtkActor> actor = vtkSmartPointer<vtkActor>::New();
|
||||
actor->GetProperty()->SetInterpolationToFlat();
|
||||
actor->GetProperty()->BackfaceCullingOn();
|
||||
actor->SetMapper(mapper);
|
||||
|
||||
WidgetAccessor::setProp(*this, actor);
|
||||
}
|
||||
|
||||
void cv::viz::WWidgetMerger::addWidget(const Widget3D& widget, const Affine3d &pose)
|
||||
{
|
||||
vtkActor *widget_actor = vtkActor::SafeDownCast(WidgetAccessor::getProp(widget));
|
||||
CV_Assert("Widget is not 3D actor." && widget_actor);
|
||||
|
||||
vtkSmartPointer<vtkPolyDataMapper> widget_mapper = vtkPolyDataMapper::SafeDownCast(widget_actor->GetMapper());
|
||||
CV_Assert("Widget doesn't have a polydata mapper" && widget_mapper);
|
||||
widget_mapper->Update();
|
||||
|
||||
vtkSmartPointer<vtkActor> actor = vtkActor::SafeDownCast(WidgetAccessor::getProp(*this));
|
||||
vtkSmartPointer<vtkAlgorithm> producer = actor->GetMapper()->GetInputConnection(0, 0)->GetProducer();
|
||||
vtkSmartPointer<vtkAppendPolyData> append_filter = vtkAppendPolyData::SafeDownCast(producer);
|
||||
CV_Assert("Correctness check" && append_filter);
|
||||
|
||||
VtkUtils::AddInputData(append_filter, VtkUtils::TransformPolydata(widget_mapper->GetInput(), pose));
|
||||
}
|
||||
|
||||
void cv::viz::WWidgetMerger::finalize()
|
||||
{
|
||||
vtkSmartPointer<vtkActor> actor = vtkActor::SafeDownCast(WidgetAccessor::getProp(*this));
|
||||
vtkSmartPointer<vtkAlgorithm> producer = actor->GetMapper()->GetInputConnection(0, 0)->GetProducer();
|
||||
vtkSmartPointer<vtkAppendPolyData> append_filter = vtkAppendPolyData::SafeDownCast(producer);
|
||||
CV_Assert("Correctness check" && append_filter);
|
||||
append_filter->Update();
|
||||
|
||||
vtkSmartPointer<vtkPolyDataMapper> mapper = vtkPolyDataMapper::SafeDownCast(actor->GetMapper());
|
||||
mapper->RemoveInputConnection(0, 0);
|
||||
VtkUtils::SetInputData(mapper, append_filter->GetOutput());
|
||||
mapper->Modified();
|
||||
}
|
||||
|
||||
template<> CV_EXPORTS cv::viz::WWidgetMerger cv::viz::Widget::cast<cv::viz::WWidgetMerger>() const
|
||||
{
|
||||
Widget3D widget = this->cast<Widget3D>();
|
||||
return static_cast<WWidgetMerger&>(widget);
|
||||
}
|
|
@ -0,0 +1,350 @@
|
|||
/*M///////////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
|
||||
//
|
||||
// By downloading, copying, installing or using the software you agree to this license.
|
||||
// If you do not agree to this license, do not download, install,
|
||||
// copy or use the software.
|
||||
//
|
||||
//
|
||||
// License Agreement
|
||||
// For Open Source Computer Vision Library
|
||||
//
|
||||
// Copyright (C) 2013, OpenCV Foundation, all rights reserved.
|
||||
// Third party copyrights are property of their respective owners.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without modification,
|
||||
// are permitted provided that the following conditions are met:
|
||||
//
|
||||
// * Redistribution's of source code must retain the above copyright notice,
|
||||
// this list of conditions and the following disclaimer.
|
||||
//
|
||||
// * Redistribution's in binary form must reproduce the above copyright notice,
|
||||
// this list of conditions and the following disclaimer in the documentation
|
||||
// and/or other materials provided with the distribution.
|
||||
//
|
||||
// * The name of the copyright holders may not be used to endorse or promote products
|
||||
// derived from this software without specific prior written permission.
|
||||
//
|
||||
// This software is provided by the copyright holders and contributors "as is" and
|
||||
// any express or implied warranties, including, but not limited to, the implied
|
||||
// warranties of merchantability and fitness for a particular purpose are disclaimed.
|
||||
// In no event shall the Intel Corporation or contributors be liable for any direct,
|
||||
// indirect, incidental, special, exemplary, or consequential damages
|
||||
// (including, but not limited to, procurement of substitute goods or services;
|
||||
// loss of use, data, or profits; or business interruption) however caused
|
||||
// and on any theory of liability, whether in contract, strict liability,
|
||||
// or tort (including negligence or otherwise) arising in any way out of
|
||||
// the use of this software, even if advised of the possibility of such damage.
|
||||
//
|
||||
// Authors:
|
||||
// * Ozan Tonkal, ozantonkal@gmail.com
|
||||
// * Anatoly Baksheev, Itseez Inc. myname.mysurname <> mycompany.com
|
||||
//
|
||||
//M*/
|
||||
|
||||
#ifndef __OPENCV_VIZ_PRECOMP_HPP__
|
||||
#define __OPENCV_VIZ_PRECOMP_HPP__
|
||||
|
||||
#include <map>
|
||||
#include <ctime>
|
||||
#include <list>
|
||||
#include <vector>
|
||||
#include <iomanip>
|
||||
#include <limits>
|
||||
|
||||
#include <vtkVersionMacros.h>
|
||||
#include <vtkAppendPolyData.h>
|
||||
#include <vtkAssemblyPath.h>
|
||||
#include <vtkCellData.h>
|
||||
#include <vtkLineSource.h>
|
||||
#include <vtkPropPicker.h>
|
||||
#include <vtkSmartPointer.h>
|
||||
#include <vtkDataSet.h>
|
||||
#include <vtkPolygon.h>
|
||||
#include <vtkUnstructuredGrid.h>
|
||||
#include <vtkDiskSource.h>
|
||||
#include <vtkPlaneSource.h>
|
||||
#include <vtkSphereSource.h>
|
||||
#include <vtkArrowSource.h>
|
||||
#include <vtkOutlineSource.h>
|
||||
#include <vtkTransform.h>
|
||||
#include <vtkTransformPolyDataFilter.h>
|
||||
#include <vtkTubeFilter.h>
|
||||
#include <vtkCubeSource.h>
|
||||
#include <vtkAxes.h>
|
||||
#include <vtkFloatArray.h>
|
||||
#include <vtkDoubleArray.h>
|
||||
#include <vtkPointData.h>
|
||||
#include <vtkPolyData.h>
|
||||
#include <vtkPolyDataMapper.h>
|
||||
#include <vtkDataSetMapper.h>
|
||||
#include <vtkCellArray.h>
|
||||
#include <vtkCommand.h>
|
||||
#include <vtkPLYReader.h>
|
||||
#include <vtkPolyLine.h>
|
||||
#include <vtkVectorText.h>
|
||||
#include <vtkFollower.h>
|
||||
#include <vtkInteractorStyle.h>
|
||||
#include <vtkUnsignedCharArray.h>
|
||||
#include <vtkRendererCollection.h>
|
||||
#include <vtkPNGWriter.h>
|
||||
#include <vtkWindowToImageFilter.h>
|
||||
#include <vtkInteractorStyleTrackballCamera.h>
|
||||
#include <vtkProperty.h>
|
||||
#include <vtkCamera.h>
|
||||
#include <vtkPlanes.h>
|
||||
#include <vtkImageFlip.h>
|
||||
#include <vtkRenderWindow.h>
|
||||
#include <vtkTextProperty.h>
|
||||
#include <vtkProperty2D.h>
|
||||
#include <vtkLODActor.h>
|
||||
#include <vtkActor.h>
|
||||
#include <vtkTextActor.h>
|
||||
#include <vtkRenderWindowInteractor.h>
|
||||
#include <vtkMath.h>
|
||||
#include <vtkExtractEdges.h>
|
||||
#include <vtkFrustumSource.h>
|
||||
#include <vtkTexture.h>
|
||||
#include <vtkTextureMapToPlane.h>
|
||||
#include <vtkPolyDataNormals.h>
|
||||
#include <vtkAlgorithmOutput.h>
|
||||
#include <vtkImageMapper.h>
|
||||
#include <vtkPoints.h>
|
||||
#include <vtkInformation.h>
|
||||
#include <vtkInformationVector.h>
|
||||
#include <vtkObjectFactory.h>
|
||||
#include <vtkPolyDataAlgorithm.h>
|
||||
#include <vtkMergeFilter.h>
|
||||
#include <vtkErrorCode.h>
|
||||
#include <vtkPLYWriter.h>
|
||||
#include <vtkSTLWriter.h>
|
||||
#include <vtkPLYReader.h>
|
||||
#include <vtkOBJReader.h>
|
||||
#include <vtkSTLReader.h>
|
||||
#include <vtkPNGReader.h>
|
||||
#include <vtkOBJExporter.h>
|
||||
#include <vtkVRMLExporter.h>
|
||||
#include <vtkTensorGlyph.h>
|
||||
#include <vtkImageAlgorithm.h>
|
||||
#include <vtkTransformFilter.h>
|
||||
#include <vtkConeSource.h>
|
||||
#include <vtkElevationFilter.h>
|
||||
#include <vtkColorTransferFunction.h>
|
||||
#include <vtkStreamingDemandDrivenPipeline.h>
|
||||
#include <vtkLight.h>
|
||||
#include <vtkCallbackCommand.h>
|
||||
#include <vtkVersion.h>
|
||||
|
||||
#if !defined(_WIN32) || defined(__CYGWIN__)
|
||||
# include <unistd.h> /* unlink */
|
||||
#else
|
||||
# include <io.h> /* unlink */
|
||||
#endif
|
||||
|
||||
#include "vtk/vtkOBJWriter.h"
|
||||
#include "vtk/vtkXYZWriter.h"
|
||||
#include "vtk/vtkXYZReader.h"
|
||||
#include "vtk/vtkCloudMatSink.h"
|
||||
#include "vtk/vtkCloudMatSource.h"
|
||||
#include "vtk/vtkTrajectorySource.h"
|
||||
#include "vtk/vtkImageMatSource.h"
|
||||
|
||||
#if VTK_MAJOR_VERSION >= 9
|
||||
typedef vtkIdType const * CellIterT;
|
||||
#else
|
||||
typedef vtkIdType * CellIterT;
|
||||
#endif
|
||||
|
||||
#include <opencv2/core.hpp>
|
||||
#include <opencv2/viz.hpp>
|
||||
#include <opencv2/viz/widget_accessor.hpp>
|
||||
#include <opencv2/core/utility.hpp>
|
||||
|
||||
|
||||
namespace cv
|
||||
{
|
||||
namespace viz
|
||||
{
|
||||
typedef std::map<String, vtkSmartPointer<vtkProp> > WidgetActorMap;
|
||||
|
||||
struct VizMap
|
||||
{
|
||||
typedef std::map<String, Viz3d> type;
|
||||
typedef type::iterator iterator;
|
||||
|
||||
type m;
|
||||
~VizMap();
|
||||
void replace_clear();
|
||||
};
|
||||
|
||||
class VizStorage
|
||||
{
|
||||
public:
|
||||
static void unregisterAll();
|
||||
|
||||
//! window names automatically have Viz - prefix even though not provided by the users
|
||||
static String generateWindowName(const String &window_name);
|
||||
|
||||
private:
|
||||
VizStorage(); // Static
|
||||
|
||||
static void add(const Viz3d& window);
|
||||
static Viz3d& get(const String &window_name);
|
||||
static void remove(const String &window_name);
|
||||
static bool windowExists(const String &window_name);
|
||||
static void removeUnreferenced();
|
||||
|
||||
static VizMap storage;
|
||||
friend class Viz3d;
|
||||
|
||||
static VizStorage init;
|
||||
};
|
||||
|
||||
template<typename _Tp> inline _Tp normalized(const _Tp& v) { return v * 1/norm(v); }
|
||||
|
||||
template<typename _Tp> inline bool isNan(const _Tp* data)
|
||||
{
|
||||
return isNan(data[0]) || isNan(data[1]) || isNan(data[2]);
|
||||
}
|
||||
|
||||
inline vtkSmartPointer<vtkActor> getActor(const Widget3D& widget)
|
||||
{
|
||||
return vtkActor::SafeDownCast(WidgetAccessor::getProp(widget));
|
||||
}
|
||||
|
||||
inline vtkSmartPointer<vtkPolyData> getPolyData(const Widget3D& widget)
|
||||
{
|
||||
vtkSmartPointer<vtkMapper> mapper = getActor(widget)->GetMapper();
|
||||
return vtkPolyData::SafeDownCast(mapper->GetInput());
|
||||
}
|
||||
|
||||
inline vtkSmartPointer<vtkMatrix4x4> vtkmatrix(const cv::Matx44d &matrix)
|
||||
{
|
||||
vtkSmartPointer<vtkMatrix4x4> vtk_matrix = vtkSmartPointer<vtkMatrix4x4>::New();
|
||||
vtk_matrix->DeepCopy(matrix.val);
|
||||
return vtk_matrix;
|
||||
}
|
||||
|
||||
inline Color vtkcolor(const Color& color)
|
||||
{
|
||||
Color scaled_color = color * (1.0/255.0);
|
||||
std::swap(scaled_color[0], scaled_color[2]);
|
||||
return scaled_color;
|
||||
}
|
||||
|
||||
inline Vec3d get_random_vec(double from = -10.0, double to = 10.0)
|
||||
{
|
||||
RNG& rng = theRNG();
|
||||
return Vec3d(rng.uniform(from, to), rng.uniform(from, to), rng.uniform(from, to));
|
||||
}
|
||||
|
||||
struct VtkUtils
|
||||
{
|
||||
template<class Filter>
|
||||
static void SetInputData(vtkSmartPointer<Filter> filter, vtkPolyData* polydata)
|
||||
{
|
||||
#if VTK_MAJOR_VERSION <= 5
|
||||
filter->SetInput(polydata);
|
||||
#else
|
||||
filter->SetInputData(polydata);
|
||||
#endif
|
||||
}
|
||||
template<class Filter>
|
||||
static void SetSourceData(vtkSmartPointer<Filter> filter, vtkPolyData* polydata)
|
||||
{
|
||||
#if VTK_MAJOR_VERSION <= 5
|
||||
filter->SetSource(polydata);
|
||||
#else
|
||||
filter->SetSourceData(polydata);
|
||||
#endif
|
||||
}
|
||||
|
||||
template<class Filter>
|
||||
static void SetInputData(vtkSmartPointer<Filter> filter, vtkImageData* polydata)
|
||||
{
|
||||
#if VTK_MAJOR_VERSION <= 5
|
||||
filter->SetInput(polydata);
|
||||
#else
|
||||
filter->SetInputData(polydata);
|
||||
#endif
|
||||
}
|
||||
|
||||
template<class Filter>
|
||||
static void AddInputData(vtkSmartPointer<Filter> filter, vtkPolyData *polydata)
|
||||
{
|
||||
#if VTK_MAJOR_VERSION <= 5
|
||||
filter->AddInput(polydata);
|
||||
#else
|
||||
filter->AddInputData(polydata);
|
||||
#endif
|
||||
}
|
||||
|
||||
static vtkSmartPointer<vtkUnsignedCharArray> FillScalars(size_t size, const Color& color)
|
||||
{
|
||||
Vec3b rgb = Vec3d(color[2], color[1], color[0]);
|
||||
Vec3b* color_data = new Vec3b[size];
|
||||
std::fill(color_data, color_data + size, rgb);
|
||||
|
||||
vtkSmartPointer<vtkUnsignedCharArray> scalars = vtkSmartPointer<vtkUnsignedCharArray>::New();
|
||||
scalars->SetName("Colors");
|
||||
scalars->SetNumberOfComponents(3);
|
||||
scalars->SetNumberOfTuples((vtkIdType)size);
|
||||
scalars->SetArray(color_data->val, (vtkIdType)(size * 3), 0, vtkUnsignedCharArray::VTK_DATA_ARRAY_DELETE);
|
||||
return scalars;
|
||||
}
|
||||
|
||||
static vtkSmartPointer<vtkPolyData> FillScalars(vtkSmartPointer<vtkPolyData> polydata, const Color& color)
|
||||
{
|
||||
return polydata->GetPointData()->SetScalars(FillScalars(polydata->GetNumberOfPoints(), color)), polydata;
|
||||
}
|
||||
|
||||
static vtkSmartPointer<vtkPolyData> ComputeNormals(vtkSmartPointer<vtkPolyData> polydata)
|
||||
{
|
||||
vtkSmartPointer<vtkPolyDataNormals> normals_generator = vtkSmartPointer<vtkPolyDataNormals>::New();
|
||||
normals_generator->ComputePointNormalsOn();
|
||||
normals_generator->ComputeCellNormalsOff();
|
||||
normals_generator->SetFeatureAngle(0.1);
|
||||
normals_generator->SetSplitting(0);
|
||||
normals_generator->SetConsistency(1);
|
||||
normals_generator->SetAutoOrientNormals(0);
|
||||
normals_generator->SetFlipNormals(0);
|
||||
normals_generator->SetNonManifoldTraversal(1);
|
||||
VtkUtils::SetInputData(normals_generator, polydata);
|
||||
normals_generator->Update();
|
||||
return normals_generator->GetOutput();
|
||||
}
|
||||
|
||||
static vtkSmartPointer<vtkPolyData> TransformPolydata(vtkSmartPointer<vtkAlgorithmOutput> algorithm_output_port, const Affine3d& pose)
|
||||
{
|
||||
vtkSmartPointer<vtkTransform> transform = vtkSmartPointer<vtkTransform>::New();
|
||||
transform->SetMatrix(vtkmatrix(pose.matrix));
|
||||
|
||||
vtkSmartPointer<vtkTransformPolyDataFilter> transform_filter = vtkSmartPointer<vtkTransformPolyDataFilter>::New();
|
||||
transform_filter->SetTransform(transform);
|
||||
transform_filter->SetInputConnection(algorithm_output_port);
|
||||
transform_filter->Update();
|
||||
return transform_filter->GetOutput();
|
||||
}
|
||||
|
||||
static vtkSmartPointer<vtkPolyData> TransformPolydata(vtkSmartPointer<vtkPolyData> polydata, const Affine3d& pose)
|
||||
{
|
||||
vtkSmartPointer<vtkTransform> transform = vtkSmartPointer<vtkTransform>::New();
|
||||
transform->SetMatrix(vtkmatrix(pose.matrix));
|
||||
|
||||
vtkSmartPointer<vtkTransformPolyDataFilter> transform_filter = vtkSmartPointer<vtkTransformPolyDataFilter>::New();
|
||||
VtkUtils::SetInputData(transform_filter, polydata);
|
||||
transform_filter->SetTransform(transform);
|
||||
transform_filter->Update();
|
||||
return transform_filter->GetOutput();
|
||||
}
|
||||
};
|
||||
|
||||
vtkSmartPointer<vtkRenderWindowInteractor> vtkCocoaRenderWindowInteractorNew();
|
||||
}
|
||||
}
|
||||
|
||||
#include "vtk/vtkVizInteractorStyle.hpp"
|
||||
#include "vizimpl.hpp"
|
||||
|
||||
#endif
|
|
@ -0,0 +1,230 @@
|
|||
/*M///////////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
|
||||
//
|
||||
// By downloading, copying, installing or using the software you agree to this license.
|
||||
// If you do not agree to this license, do not download, install,
|
||||
// copy or use the software.
|
||||
//
|
||||
//
|
||||
// License Agreement
|
||||
// For Open Source Computer Vision Library
|
||||
//
|
||||
// Copyright (C) 2013, OpenCV Foundation, all rights reserved.
|
||||
// Third party copyrights are property of their respective owners.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without modification,
|
||||
// are permitted provided that the following conditions are met:
|
||||
//
|
||||
// * Redistribution's of source code must retain the above copyright notice,
|
||||
// this list of conditions and the following disclaimer.
|
||||
//
|
||||
// * Redistribution's in binary form must reproduce the above copyright notice,
|
||||
// this list of conditions and the following disclaimer in the documentation
|
||||
// and/or other materials provided with the distribution.
|
||||
//
|
||||
// * The name of the copyright holders may not be used to endorse or promote products
|
||||
// derived from this software without specific prior written permission.
|
||||
//
|
||||
// This software is provided by the copyright holders and contributors "as is" and
|
||||
// any express or implied warranties, including, but not limited to, the implied
|
||||
// warranties of merchantability and fitness for a particular purpose are disclaimed.
|
||||
// In no event shall the Intel Corporation or contributors be liable for any direct,
|
||||
// indirect, incidental, special, exemplary, or consequential damages
|
||||
// (including, but not limited to, procurement of substitute goods or services;
|
||||
// loss of use, data, or profits; or business interruption) however caused
|
||||
// and on any theory of liability, whether in contract, strict liability,
|
||||
// or tort (including negligence or otherwise) arising in any way out of
|
||||
// the use of this software, even if advised of the possibility of such damage.
|
||||
//
|
||||
// Authors:
|
||||
// * Ozan Tonkal, ozantonkal@gmail.com
|
||||
// * Anatoly Baksheev, Itseez Inc. myname.mysurname <> mycompany.com
|
||||
//
|
||||
//M*/
|
||||
|
||||
#include "precomp.hpp"
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
/// Events
|
||||
|
||||
cv::viz::KeyboardEvent::KeyboardEvent(Action _action, const String& _symbol, unsigned char _code, int _modifiers)
|
||||
: action(_action), symbol(_symbol), code(_code), modifiers(_modifiers) {}
|
||||
|
||||
cv::viz::MouseEvent::MouseEvent(const Type& _type, const MouseButton& _button, const Point& _pointer, int _modifiers)
|
||||
: type(_type), button(_button), pointer(_pointer), modifiers(_modifiers) {}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
/// cv::viz::Mesh3d
|
||||
|
||||
cv::viz::Mesh cv::viz::Mesh::load(const String& file, int type)
|
||||
{
|
||||
vtkSmartPointer<vtkPolyDataAlgorithm> reader = vtkSmartPointer<vtkPolyDataAlgorithm>::New();
|
||||
switch (type) {
|
||||
case LOAD_AUTO:
|
||||
{
|
||||
CV_Error(Error::StsError, "cv::viz::Mesh::LOAD_AUTO: Not implemented yet");
|
||||
}
|
||||
case LOAD_PLY:
|
||||
{
|
||||
vtkSmartPointer<vtkPLYReader> ply_reader = vtkSmartPointer<vtkPLYReader>::New();
|
||||
ply_reader->SetFileName(file.c_str());
|
||||
ply_reader->Update();
|
||||
reader = ply_reader;
|
||||
break;
|
||||
}
|
||||
case LOAD_OBJ:
|
||||
{
|
||||
vtkSmartPointer<vtkOBJReader> obj_reader = vtkSmartPointer<vtkOBJReader>::New();
|
||||
obj_reader->SetFileName(file.c_str());
|
||||
obj_reader->Update();
|
||||
reader = obj_reader;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
CV_Error(Error::StsError, "cv::viz::Mesh::load: Unknown file type");
|
||||
}
|
||||
|
||||
vtkSmartPointer<vtkPolyData> polydata = reader->GetOutput();
|
||||
CV_Assert("File does not exist or file format is not supported." && polydata);
|
||||
|
||||
Mesh mesh;
|
||||
vtkSmartPointer<vtkCloudMatSink> sink = vtkSmartPointer<vtkCloudMatSink>::New();
|
||||
sink->SetOutput(mesh.cloud, mesh.colors, mesh.normals, mesh.tcoords);
|
||||
sink->SetInputConnection(reader->GetOutputPort());
|
||||
sink->Write();
|
||||
|
||||
// Now handle the polygons
|
||||
vtkSmartPointer<vtkCellArray> polygons = polydata->GetPolys();
|
||||
mesh.polygons.create(1, polygons->GetSize(), CV_32SC1);
|
||||
mesh.polygons = 0;
|
||||
int* poly_ptr = mesh.polygons.ptr<int>();
|
||||
|
||||
polygons->InitTraversal();
|
||||
vtkIdType nr_cell_points;
|
||||
CellIterT cell_points;
|
||||
while (polygons->GetNextCell(nr_cell_points, cell_points))
|
||||
{
|
||||
*poly_ptr++ = nr_cell_points;
|
||||
for (vtkIdType i = 0; i < nr_cell_points; ++i)
|
||||
*poly_ptr++ = (int)cell_points[i];
|
||||
}
|
||||
|
||||
return mesh;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
/// Camera implementation
|
||||
|
||||
cv::viz::Camera::Camera(double fx, double fy, double cx, double cy, const Size &window_size)
|
||||
{
|
||||
init(fx, fy, cx, cy, window_size);
|
||||
}
|
||||
|
||||
cv::viz::Camera::Camera(const Vec2d &fov, const Size &window_size)
|
||||
{
|
||||
CV_Assert(window_size.width > 0 && window_size.height > 0);
|
||||
setClip(Vec2d(0.01, 1000.01)); // Default clipping
|
||||
setFov(fov);
|
||||
window_size_ = window_size;
|
||||
// Principal point at the center
|
||||
principal_point_ = Vec2f(static_cast<float>(window_size.width)*0.5f, static_cast<float>(window_size.height)*0.5f);
|
||||
focal_ = Vec2f(principal_point_[0] / tan(fov_[0]*0.5f), principal_point_[1] / tan(fov_[1]*0.5f));
|
||||
}
|
||||
|
||||
cv::viz::Camera::Camera(const cv::Matx33d & K, const Size &window_size)
|
||||
{
|
||||
double f_x = K(0,0);
|
||||
double f_y = K(1,1);
|
||||
double c_x = K(0,2);
|
||||
double c_y = K(1,2);
|
||||
init(f_x, f_y, c_x, c_y, window_size);
|
||||
}
|
||||
|
||||
cv::viz::Camera::Camera(const Matx44d &proj, const Size &window_size)
|
||||
{
|
||||
CV_Assert(window_size.width > 0 && window_size.height > 0);
|
||||
|
||||
double near = proj(2,3) / (proj(2,2) - 1.0);
|
||||
double far = near * (proj(2,2) - 1.0) / (proj(2,2) + 1.0);
|
||||
double left = near * (proj(0,2)-1) / proj(0,0);
|
||||
double right = 2.0 * near / proj(0,0) + left;
|
||||
double bottom = near * (proj(1,2)-1) / proj(1,1);
|
||||
double top = 2.0 * near / proj(1,1) + bottom;
|
||||
|
||||
double epsilon = 2.2204460492503131e-16;
|
||||
|
||||
principal_point_[0] = fabs(left-right) < epsilon ? window_size.width * 0.5 : (left * window_size.width) / (left - right);
|
||||
principal_point_[1] = fabs(top-bottom) < epsilon ? window_size.height * 0.5 : (top * window_size.height) / (top - bottom);
|
||||
|
||||
focal_[0] = -near * principal_point_[0] / left;
|
||||
focal_[1] = near * principal_point_[1] / top;
|
||||
|
||||
setClip(Vec2d(near, far));
|
||||
fov_[0] = atan2(principal_point_[0], focal_[0]) + atan2(window_size.width-principal_point_[0], focal_[0]);
|
||||
fov_[1] = atan2(principal_point_[1], focal_[1]) + atan2(window_size.height-principal_point_[1], focal_[1]);
|
||||
|
||||
window_size_ = window_size;
|
||||
}
|
||||
|
||||
void cv::viz::Camera::init(double fx, double fy, double cx, double cy, const Size &window_size)
|
||||
{
|
||||
CV_Assert(window_size.width > 0 && window_size.height > 0);
|
||||
setClip(Vec2d(0.01, 1000.01));// Default clipping
|
||||
|
||||
fov_[0] = atan2(cx, fx) + atan2(window_size.width - cx, fx);
|
||||
fov_[1] = atan2(cy, fy) + atan2(window_size.height - cy, fy);
|
||||
|
||||
principal_point_[0] = cx;
|
||||
principal_point_[1] = cy;
|
||||
|
||||
focal_[0] = fx;
|
||||
focal_[1] = fy;
|
||||
|
||||
window_size_ = window_size;
|
||||
}
|
||||
|
||||
void cv::viz::Camera::setWindowSize(const Size &window_size)
|
||||
{
|
||||
CV_Assert(window_size.width > 0 && window_size.height > 0);
|
||||
|
||||
// Get the scale factor and update the principal points
|
||||
float scalex = static_cast<float>(window_size.width) / static_cast<float>(window_size_.width);
|
||||
float scaley = static_cast<float>(window_size.height) / static_cast<float>(window_size_.height);
|
||||
|
||||
principal_point_[0] *= scalex;
|
||||
principal_point_[1] *= scaley;
|
||||
focal_ *= scaley;
|
||||
// Vertical field of view is fixed! Update horizontal field of view
|
||||
fov_[0] = (atan2(principal_point_[0],focal_[0]) + atan2(window_size.width-principal_point_[0],focal_[0]));
|
||||
|
||||
window_size_ = window_size;
|
||||
}
|
||||
|
||||
void cv::viz::Camera::computeProjectionMatrix(Matx44d &proj) const
|
||||
{
|
||||
double top = clip_[0] * principal_point_[1] / focal_[1];
|
||||
double left = -clip_[0] * principal_point_[0] / focal_[0];
|
||||
double right = clip_[0] * (window_size_.width - principal_point_[0]) / focal_[0];
|
||||
double bottom = -clip_[0] * (window_size_.height - principal_point_[1]) / focal_[1];
|
||||
|
||||
double temp1 = 2.0 * clip_[0];
|
||||
double temp2 = 1.0 / (right - left);
|
||||
double temp3 = 1.0 / (top - bottom);
|
||||
double temp4 = 1.0 / (clip_[0] - clip_[1]);
|
||||
|
||||
proj = Matx44d::zeros();
|
||||
proj(0,0) = temp1 * temp2;
|
||||
proj(1,1) = temp1 * temp3;
|
||||
proj(0,2) = (right + left) * temp2;
|
||||
proj(1,2) = (top + bottom) * temp3;
|
||||
proj(2,2) = (clip_[1]+clip_[0]) * temp4;
|
||||
proj(3,2) = -1.0;
|
||||
proj(2,3) = (temp1 * clip_[1]) * temp4;
|
||||
}
|
||||
|
||||
cv::viz::Camera cv::viz::Camera::KinectCamera(const Size &window_size)
|
||||
{
|
||||
Matx33d K(525.0, 0.0, 320.0, 0.0, 525.0, 240.0, 0.0, 0.0, 1.0);
|
||||
return Camera(K, window_size);
|
||||
}
|
|
@ -0,0 +1,156 @@
|
|||
/*M///////////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
|
||||
//
|
||||
// By downloading, copying, installing or using the software you agree to this license.
|
||||
// If you do not agree to this license, do not download, install,
|
||||
// copy or use the software.
|
||||
//
|
||||
//
|
||||
// License Agreement
|
||||
// For Open Source Computer Vision Library
|
||||
//
|
||||
// Copyright (C) 2013, OpenCV Foundation, all rights reserved.
|
||||
// Third party copyrights are property of their respective owners.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without modification,
|
||||
// are permitted provided that the following conditions are met:
|
||||
//
|
||||
// * Redistribution's of source code must retain the above copyright notice,
|
||||
// this list of conditions and the following disclaimer.
|
||||
//
|
||||
// * Redistribution's in binary form must reproduce the above copyright notice,
|
||||
// this list of conditions and the following disclaimer in the documentation
|
||||
// and/or other materials provided with the distribution.
|
||||
//
|
||||
// * The name of the copyright holders may not be used to endorse or promote products
|
||||
// derived from this software without specific prior written permission.
|
||||
//
|
||||
// This software is provided by the copyright holders and contributors "as is" and
|
||||
// any express or implied warranties, including, but not limited to, the implied
|
||||
// warranties of merchantability and fitness for a particular purpose are disclaimed.
|
||||
// In no event shall the Intel Corporation or contributors be liable for any direct,
|
||||
// indirect, incidental, special, exemplary, or consequential damages
|
||||
// (including, but not limited to, procurement of substitute goods or services;
|
||||
// loss of use, data, or profits; or business interruption) however caused
|
||||
// and on any theory of liability, whether in contract, strict liability,
|
||||
// or tort (including negligence or otherwise) arising in any way out of
|
||||
// the use of this software, even if advised of the possibility of such damage.
|
||||
//
|
||||
// Authors:
|
||||
// * Ozan Tonkal, ozantonkal@gmail.com
|
||||
// * Anatoly Baksheev, Itseez Inc. myname.mysurname <> mycompany.com
|
||||
//
|
||||
//M*/
|
||||
|
||||
#include "precomp.hpp"
|
||||
|
||||
cv::viz::Viz3d::Viz3d(const String& window_name) : impl_(0) { create(window_name); }
|
||||
|
||||
cv::viz::Viz3d::Viz3d(const Viz3d& other) : impl_(other.impl_)
|
||||
{
|
||||
if (impl_)
|
||||
CV_XADD(&impl_->ref_counter, 1);
|
||||
}
|
||||
|
||||
cv::viz::Viz3d& cv::viz::Viz3d::operator=(const Viz3d& other)
|
||||
{
|
||||
if (this != &other)
|
||||
{
|
||||
release();
|
||||
impl_ = other.impl_;
|
||||
if (impl_)
|
||||
CV_XADD(&impl_->ref_counter, 1);
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
cv::viz::Viz3d::~Viz3d() { release(); }
|
||||
|
||||
void cv::viz::Viz3d::create(const String &window_name)
|
||||
{
|
||||
if (impl_)
|
||||
release();
|
||||
|
||||
if (VizStorage::windowExists(window_name))
|
||||
*this = VizStorage::get(window_name);
|
||||
else
|
||||
{
|
||||
impl_ = new VizImpl(window_name);
|
||||
impl_->ref_counter = 1;
|
||||
|
||||
// Register the window
|
||||
VizStorage::add(*this);
|
||||
}
|
||||
}
|
||||
|
||||
void cv::viz::Viz3d::release()
|
||||
{
|
||||
if (impl_ && CV_XADD(&impl_->ref_counter, -1) == 1)
|
||||
{
|
||||
delete impl_;
|
||||
impl_ = 0;
|
||||
}
|
||||
|
||||
if (impl_ && impl_->ref_counter == 1)
|
||||
VizStorage::removeUnreferenced();
|
||||
|
||||
impl_ = 0;
|
||||
}
|
||||
|
||||
void cv::viz::Viz3d::spin() { impl_->spin(); }
|
||||
void cv::viz::Viz3d::spinOnce(int time, bool force_redraw) { impl_->spinOnce(time, force_redraw); }
|
||||
void cv::viz::Viz3d::setOffScreenRendering() { impl_->setOffScreenRendering(); }
|
||||
void cv::viz::Viz3d::removeAllLights() { impl_->removeAllLights(); }
|
||||
void cv::viz::Viz3d::addLight(const Vec3d &position, const Vec3d &focalPoint, const Color &color,
|
||||
const Color &diffuseColor, const Color &ambientColor, const Color &specularColor)
|
||||
{ impl_->addLight(position, focalPoint, color, diffuseColor, ambientColor, specularColor); }
|
||||
bool cv::viz::Viz3d::wasStopped() const { return impl_->wasStopped(); }
|
||||
void cv::viz::Viz3d::close() { impl_->close(); }
|
||||
|
||||
void cv::viz::Viz3d::registerKeyboardCallback(KeyboardCallback callback, void* cookie)
|
||||
{ impl_->registerKeyboardCallback(callback, cookie); }
|
||||
|
||||
void cv::viz::Viz3d::registerMouseCallback(MouseCallback callback, void* cookie)
|
||||
{ impl_->registerMouseCallback(callback, cookie); }
|
||||
|
||||
void cv::viz::Viz3d::showWidget(const String &id, const Widget &widget, const Affine3d &pose) { impl_->showWidget(id, widget, pose); }
|
||||
void cv::viz::Viz3d::removeWidget(const String &id) { impl_->removeWidget(id); }
|
||||
cv::viz::Widget cv::viz::Viz3d::getWidget(const String &id) const { return impl_->getWidget(id); }
|
||||
void cv::viz::Viz3d::removeAllWidgets() { impl_->removeAllWidgets(); }
|
||||
|
||||
void cv::viz::Viz3d::showImage(InputArray image, const Size& window_size) { impl_->showImage(image, window_size); }
|
||||
|
||||
void cv::viz::Viz3d::setWidgetPose(const String &id, const Affine3d &pose) { impl_->setWidgetPose(id, pose); }
|
||||
void cv::viz::Viz3d::updateWidgetPose(const String &id, const Affine3d &pose) { impl_->updateWidgetPose(id, pose); }
|
||||
cv::Affine3d cv::viz::Viz3d::getWidgetPose(const String &id) const { return impl_->getWidgetPose(id); }
|
||||
|
||||
void cv::viz::Viz3d::setCamera(const Camera &camera) { impl_->setCamera(camera); }
|
||||
cv::viz::Camera cv::viz::Viz3d::getCamera() const { return impl_->getCamera(); }
|
||||
void cv::viz::Viz3d::setViewerPose(const Affine3d &pose) { impl_->setViewerPose(pose); }
|
||||
cv::Affine3d cv::viz::Viz3d::getViewerPose() const { return impl_->getViewerPose(); }
|
||||
|
||||
void cv::viz::Viz3d::resetCameraViewpoint(const String &id) { impl_->resetCameraViewpoint(id); }
|
||||
void cv::viz::Viz3d::resetCamera() { impl_->resetCamera(); }
|
||||
|
||||
void cv::viz::Viz3d::convertToWindowCoordinates(const Point3d &pt, Point3d &window_coord) { impl_->convertToWindowCoordinates(pt, window_coord); }
|
||||
void cv::viz::Viz3d::converTo3DRay(const Point3d &window_coord, Point3d &origin, Vec3d &direction) { impl_->converTo3DRay(window_coord, origin, direction); }
|
||||
|
||||
cv::Size cv::viz::Viz3d::getWindowSize() const { return impl_->getWindowSize(); }
|
||||
void cv::viz::Viz3d::setWindowSize(const Size &window_size) { impl_->setWindowSize(window_size); }
|
||||
cv::String cv::viz::Viz3d::getWindowName() const { return impl_->getWindowName(); }
|
||||
cv::Mat cv::viz::Viz3d::getScreenshot() const { return impl_->getScreenshot(); }
|
||||
void cv::viz::Viz3d::saveScreenshot(const String &file) { impl_->saveScreenshot(file); }
|
||||
void cv::viz::Viz3d::setWindowPosition(const Point& window_position) { impl_->setWindowPosition(window_position); }
|
||||
void cv::viz::Viz3d::setFullScreen(bool mode) { impl_->setFullScreen(mode); }
|
||||
void cv::viz::Viz3d::setBackgroundColor(const Color& color, const Color& color2) { impl_->setBackgroundColor(color, color2); }
|
||||
|
||||
void cv::viz::Viz3d::setBackgroundTexture(InputArray image) { impl_->setBackgroundTexture(image); }
|
||||
void cv::viz::Viz3d::setBackgroundMeshLab() {impl_->setBackgroundMeshLab(); }
|
||||
|
||||
void cv::viz::Viz3d::setRenderingProperty(const String &id, int property, double value) { getWidget(id).setRenderingProperty(property, value); }
|
||||
double cv::viz::Viz3d::getRenderingProperty(const String &id, int property) { return getWidget(id).getRenderingProperty(property); }
|
||||
|
||||
void cv::viz::Viz3d::setRepresentation(int representation) { impl_->setRepresentation(representation); }
|
||||
|
||||
void cv::viz::Viz3d::setGlobalWarnings(bool enabled) { vtkObject::SetGlobalWarningDisplay(enabled ? 1 : 0); }
|
|
@ -0,0 +1,352 @@
|
|||
/*M///////////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
|
||||
//
|
||||
// By downloading, copying, installing or using the software you agree to this license.
|
||||
// If you do not agree to this license, do not download, install,
|
||||
// copy or use the software.
|
||||
//
|
||||
//
|
||||
// License Agreement
|
||||
// For Open Source Computer Vision Library
|
||||
//
|
||||
// Copyright (C) 2013, OpenCV Foundation, all rights reserved.
|
||||
// Third party copyrights are property of their respective owners.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without modification,
|
||||
// are permitted provided that the following conditions are met:
|
||||
//
|
||||
// * Redistribution's of source code must retain the above copyright notice,
|
||||
// this list of conditions and the following disclaimer.
|
||||
//
|
||||
// * Redistribution's in binary form must reproduce the above copyright notice,
|
||||
// this list of conditions and the following disclaimer in the documentation
|
||||
// and/or other materials provided with the distribution.
|
||||
//
|
||||
// * The name of the copyright holders may not be used to endorse or promote products
|
||||
// derived from this software without specific prior written permission.
|
||||
//
|
||||
// This software is provided by the copyright holders and contributors "as is" and
|
||||
// any express or implied warranties, including, but not limited to, the implied
|
||||
// warranties of merchantability and fitness for a particular purpose are disclaimed.
|
||||
// In no event shall the Intel Corporation or contributors be liable for any direct,
|
||||
// indirect, incidental, special, exemplary, or consequential damages
|
||||
// (including, but not limited to, procurement of substitute goods or services;
|
||||
// loss of use, data, or profits; or business interruption) however caused
|
||||
// and on any theory of liability, whether in contract, strict liability,
|
||||
// or tort (including negligence or otherwise) arising in any way out of
|
||||
// the use of this software, even if advised of the possibility of such damage.
|
||||
//
|
||||
// Authors:
|
||||
// * Ozan Tonkal, ozantonkal@gmail.com
|
||||
// * Anatoly Baksheev, Itseez Inc. myname.mysurname <> mycompany.com
|
||||
//
|
||||
//M*/
|
||||
|
||||
#include "precomp.hpp"
|
||||
|
||||
cv::Affine3d cv::viz::makeTransformToGlobal(const Vec3d& axis_x, const Vec3d& axis_y, const Vec3d& axis_z, const Vec3d& origin)
|
||||
{
|
||||
Affine3d::Mat3 R(axis_x[0], axis_y[0], axis_z[0],
|
||||
axis_x[1], axis_y[1], axis_z[1],
|
||||
axis_x[2], axis_y[2], axis_z[2]);
|
||||
|
||||
return Affine3d(R, origin);
|
||||
}
|
||||
|
||||
cv::Affine3d cv::viz::makeCameraPose(const Vec3d& position, const Vec3d& focal_point, const Vec3d& y_dir)
|
||||
{
|
||||
// Compute the transformation matrix for drawing the camera frame in a scene
|
||||
Vec3d n = normalize(focal_point - position);
|
||||
Vec3d u = normalize(y_dir.cross(n));
|
||||
Vec3d v = n.cross(u);
|
||||
|
||||
return makeTransformToGlobal(u, v, n, position);
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////
|
||||
/// VizStorage implementation
|
||||
|
||||
#if defined(_WIN32) && !defined(__CYGWIN__)
|
||||
|
||||
#include <windows.h>
|
||||
|
||||
static BOOL WINAPI ConsoleHandlerRoutine(DWORD /*dwCtrlType*/)
|
||||
{
|
||||
vtkObject::GlobalWarningDisplayOff();
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static void register_console_handler()
|
||||
{
|
||||
HANDLE hOut = GetStdHandle(STD_OUTPUT_HANDLE);
|
||||
CONSOLE_SCREEN_BUFFER_INFO hOutInfo;
|
||||
if (GetConsoleScreenBufferInfo(hOut, &hOutInfo))
|
||||
SetConsoleCtrlHandler(ConsoleHandlerRoutine, TRUE);
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
void register_console_handler();
|
||||
void register_console_handler() {}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
cv::viz::VizStorage cv::viz::VizStorage::init;
|
||||
cv::viz::VizMap cv::viz::VizStorage::storage;
|
||||
|
||||
void cv::viz::VizMap::replace_clear() { type().swap(m); }
|
||||
cv::viz::VizMap::~VizMap() { replace_clear(); }
|
||||
|
||||
cv::viz::VizStorage::VizStorage()
|
||||
{
|
||||
register_console_handler();
|
||||
}
|
||||
void cv::viz::VizStorage::unregisterAll() { storage.replace_clear(); }
|
||||
|
||||
cv::viz::Viz3d& cv::viz::VizStorage::get(const String &window_name)
|
||||
{
|
||||
String name = generateWindowName(window_name);
|
||||
VizMap::iterator vm_itr = storage.m.find(name);
|
||||
CV_Assert(vm_itr != storage.m.end());
|
||||
return vm_itr->second;
|
||||
}
|
||||
|
||||
void cv::viz::VizStorage::add(const Viz3d& window)
|
||||
{
|
||||
String window_name = window.getWindowName();
|
||||
VizMap::iterator vm_itr = storage.m.find(window_name);
|
||||
CV_Assert(vm_itr == storage.m.end());
|
||||
storage.m.insert(std::make_pair(window_name, window));
|
||||
}
|
||||
|
||||
bool cv::viz::VizStorage::windowExists(const String &window_name)
|
||||
{
|
||||
String name = generateWindowName(window_name);
|
||||
return storage.m.find(name) != storage.m.end();
|
||||
}
|
||||
|
||||
void cv::viz::VizStorage::removeUnreferenced()
|
||||
{
|
||||
for(VizMap::iterator pos = storage.m.begin(); pos != storage.m.end();)
|
||||
if(pos->second.impl_->ref_counter == 1)
|
||||
storage.m.erase(pos++);
|
||||
else
|
||||
++pos;
|
||||
}
|
||||
|
||||
cv::String cv::viz::VizStorage::generateWindowName(const String &window_name)
|
||||
{
|
||||
String output = "Viz";
|
||||
// Already is Viz
|
||||
if (window_name == output)
|
||||
return output;
|
||||
|
||||
String prefixed = output + " - ";
|
||||
if (window_name.substr(0, prefixed.length()) == prefixed)
|
||||
output = window_name; // Already has "Viz - "
|
||||
else if (window_name.substr(0, output.length()) == output)
|
||||
output = prefixed + window_name; // Doesn't have prefix
|
||||
else
|
||||
output = (window_name == "" ? output : prefixed + window_name);
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
cv::viz::Viz3d cv::viz::getWindowByName(const String &window_name) { return Viz3d (window_name); }
|
||||
void cv::viz::unregisterAllWindows() { VizStorage::unregisterAll(); }
|
||||
|
||||
cv::viz::Viz3d cv::viz::imshow(const String& window_name, InputArray image, const Size& window_size)
|
||||
{
|
||||
Viz3d viz = getWindowByName(window_name);
|
||||
viz.showImage(image, window_size);
|
||||
return viz;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////
|
||||
/// Read/write clouds. Supported formats: ply, stl, xyz, obj
|
||||
|
||||
void cv::viz::writeCloud(const String& file, InputArray cloud, InputArray colors, InputArray normals, bool binary)
|
||||
{
|
||||
CV_Assert(file.size() > 4 && "Extension is required");
|
||||
String extension = file.substr(file.size()-4);
|
||||
|
||||
vtkSmartPointer<vtkCloudMatSource> source = vtkSmartPointer<vtkCloudMatSource>::New();
|
||||
source->SetColorCloudNormals(cloud, colors, normals);
|
||||
|
||||
vtkSmartPointer<vtkWriter> writer;
|
||||
if (extension == ".xyz")
|
||||
{
|
||||
writer = vtkSmartPointer<vtkXYZWriter>::New();
|
||||
vtkXYZWriter::SafeDownCast(writer)->SetFileName(file.c_str());
|
||||
}
|
||||
else if (extension == ".ply")
|
||||
{
|
||||
writer = vtkSmartPointer<vtkPLYWriter>::New();
|
||||
vtkPLYWriter::SafeDownCast(writer)->SetFileName(file.c_str());
|
||||
vtkPLYWriter::SafeDownCast(writer)->SetFileType(binary ? VTK_BINARY : VTK_ASCII);
|
||||
vtkPLYWriter::SafeDownCast(writer)->SetArrayName("Colors");
|
||||
}
|
||||
else if (extension == ".obj")
|
||||
{
|
||||
writer = vtkSmartPointer<vtkOBJWriter>::New();
|
||||
vtkOBJWriter::SafeDownCast(writer)->SetFileName(file.c_str());
|
||||
}
|
||||
else
|
||||
CV_Error(Error::StsError, "Unsupported format");
|
||||
|
||||
writer->SetInputConnection(source->GetOutputPort());
|
||||
writer->Write();
|
||||
}
|
||||
|
||||
cv::Mat cv::viz::readCloud(const String& file, OutputArray colors, OutputArray normals)
|
||||
{
|
||||
CV_Assert(file.size() > 4 && "Extension is required");
|
||||
String extension = file.substr(file.size()-4);
|
||||
|
||||
vtkSmartPointer<vtkPolyDataAlgorithm> reader;
|
||||
if (extension == ".xyz")
|
||||
{
|
||||
reader = vtkSmartPointer<vtkXYZReader>::New();
|
||||
vtkXYZReader::SafeDownCast(reader)->SetFileName(file.c_str());
|
||||
}
|
||||
else if (extension == ".ply")
|
||||
{
|
||||
reader = vtkSmartPointer<vtkPLYReader>::New();
|
||||
CV_Assert(vtkPLYReader::CanReadFile(file.c_str()));
|
||||
vtkPLYReader::SafeDownCast(reader)->SetFileName(file.c_str());
|
||||
}
|
||||
else if (extension == ".obj")
|
||||
{
|
||||
reader = vtkSmartPointer<vtkOBJReader>::New();
|
||||
vtkOBJReader::SafeDownCast(reader)->SetFileName(file.c_str());
|
||||
}
|
||||
else if (extension == ".stl")
|
||||
{
|
||||
reader = vtkSmartPointer<vtkSTLReader>::New();
|
||||
vtkSTLReader::SafeDownCast(reader)->SetFileName(file.c_str());
|
||||
}
|
||||
else
|
||||
CV_Error(Error::StsError, "Unsupported format");
|
||||
|
||||
cv::Mat cloud;
|
||||
|
||||
vtkSmartPointer<vtkCloudMatSink> sink = vtkSmartPointer<vtkCloudMatSink>::New();
|
||||
sink->SetInputConnection(reader->GetOutputPort());
|
||||
sink->SetOutput(cloud, colors, normals);
|
||||
sink->Write();
|
||||
|
||||
return cloud;
|
||||
}
|
||||
|
||||
cv::viz::Mesh cv::viz::readMesh(const String& file) { return Mesh::load(file); }
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////
|
||||
/// Read/write poses and trajectories
|
||||
|
||||
bool cv::viz::readPose(const String& file, Affine3d& pose, const String& tag)
|
||||
{
|
||||
FileStorage fs(file, FileStorage::READ);
|
||||
if (!fs.isOpened())
|
||||
return false;
|
||||
|
||||
Mat hdr(pose.matrix, false);
|
||||
fs[tag] >> hdr;
|
||||
if (hdr.empty() || hdr.cols != pose.matrix.cols || hdr.rows != pose.matrix.rows)
|
||||
return false;
|
||||
|
||||
hdr.convertTo(pose.matrix, CV_64F);
|
||||
return true;
|
||||
}
|
||||
|
||||
void cv::viz::writePose(const String& file, const Affine3d& pose, const String& tag)
|
||||
{
|
||||
FileStorage fs(file, FileStorage::WRITE);
|
||||
fs << tag << Mat(pose.matrix, false);
|
||||
}
|
||||
|
||||
void cv::viz::readTrajectory(OutputArray _traj, const String& files_format, int start, int end, const String& tag)
|
||||
{
|
||||
CV_Assert(_traj.kind() == _InputArray::STD_VECTOR || _traj.kind() == _InputArray::MAT);
|
||||
|
||||
start = max(0, std::min(start, end));
|
||||
end = std::max(start, end);
|
||||
|
||||
std::vector<Affine3d> traj;
|
||||
|
||||
for(int i = start; i < end; ++i)
|
||||
{
|
||||
Affine3d affine;
|
||||
bool ok = readPose(cv::format(files_format.c_str(), i), affine, tag);
|
||||
if (!ok)
|
||||
break;
|
||||
|
||||
traj.push_back(affine);
|
||||
}
|
||||
|
||||
Mat(traj).convertTo(_traj, _traj.depth());
|
||||
}
|
||||
|
||||
void cv::viz::writeTrajectory(InputArray _traj, const String& files_format, int start, const String& tag)
|
||||
{
|
||||
if (_traj.kind() == _InputArray::STD_VECTOR_MAT)
|
||||
{
|
||||
#if CV_MAJOR_VERSION < 3
|
||||
std::vector<Mat>& v = *(std::vector<Mat>*)_traj.obj;
|
||||
#else
|
||||
std::vector<Mat>& v = *(std::vector<Mat>*)_traj.getObj();
|
||||
#endif
|
||||
|
||||
for(size_t i = 0, index = max(0, start); i < v.size(); ++i, ++index)
|
||||
{
|
||||
Affine3d affine;
|
||||
Mat pose = v[i];
|
||||
CV_Assert(pose.type() == CV_32FC(16) || pose.type() == CV_64FC(16));
|
||||
pose.copyTo(affine.matrix);
|
||||
writePose(cv::format(files_format.c_str(), index), affine, tag);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (_traj.kind() == _InputArray::STD_VECTOR || _traj.kind() == _InputArray::MAT)
|
||||
{
|
||||
CV_Assert(_traj.type() == CV_32FC(16) || _traj.type() == CV_64FC(16));
|
||||
|
||||
Mat traj = _traj.getMat();
|
||||
|
||||
if (traj.depth() == CV_32F)
|
||||
for(size_t i = 0, index = max(0, start); i < traj.total(); ++i, ++index)
|
||||
writePose(cv::format(files_format.c_str(), index), traj.at<Affine3f>((int)i), tag);
|
||||
|
||||
if (traj.depth() == CV_64F)
|
||||
for(size_t i = 0, index = max(0, start); i < traj.total(); ++i, ++index)
|
||||
writePose(cv::format(files_format.c_str(), index), traj.at<Affine3d>((int)i), tag);
|
||||
return;
|
||||
}
|
||||
|
||||
CV_Error(Error::StsError, "Unsupported array kind");
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////
|
||||
/// Computing normals for mesh
|
||||
|
||||
void cv::viz::computeNormals(const Mesh& mesh, OutputArray _normals)
|
||||
{
|
||||
vtkSmartPointer<vtkPolyData> polydata = getPolyData(WMesh(mesh));
|
||||
vtkSmartPointer<vtkPolyData> with_normals = VtkUtils::ComputeNormals(polydata);
|
||||
|
||||
vtkSmartPointer<vtkDataArray> generic_normals = with_normals->GetPointData()->GetNormals();
|
||||
if(generic_normals)
|
||||
{
|
||||
Mat normals(1, generic_normals->GetNumberOfTuples(), CV_64FC3);
|
||||
Vec3d *optr = normals.ptr<Vec3d>();
|
||||
|
||||
for(int i = 0; i < generic_normals->GetNumberOfTuples(); ++i, ++optr)
|
||||
generic_normals->GetTuple(i, optr->val);
|
||||
|
||||
normals.convertTo(_normals, mesh.cloud.type());
|
||||
}
|
||||
else
|
||||
_normals.release();
|
||||
}
|
|
@ -0,0 +1,631 @@
|
|||
/*M///////////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
|
||||
//
|
||||
// By downloading, copying, installing or using the software you agree to this license.
|
||||
// If you do not agree to this license, do not download, install,
|
||||
// copy or use the software.
|
||||
//
|
||||
//
|
||||
// License Agreement
|
||||
// For Open Source Computer Vision Library
|
||||
//
|
||||
// Copyright (C) 2013, OpenCV Foundation, all rights reserved.
|
||||
// Third party copyrights are property of their respective owners.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without modification,
|
||||
// are permitted provided that the following conditions are met:
|
||||
//
|
||||
// * Redistribution's of source code must retain the above copyright notice,
|
||||
// this list of conditions and the following disclaimer.
|
||||
//
|
||||
// * Redistribution's in binary form must reproduce the above copyright notice,
|
||||
// this list of conditions and the following disclaimer in the documentation
|
||||
// and/or other materials provided with the distribution.
|
||||
//
|
||||
// * The name of the copyright holders may not be used to endorse or promote products
|
||||
// derived from this software without specific prior written permission.
|
||||
//
|
||||
// This software is provided by the copyright holders and contributors "as is" and
|
||||
// any express or implied warranties, including, but not limited to, the implied
|
||||
// warranties of merchantability and fitness for a particular purpose are disclaimed.
|
||||
// In no event shall the Intel Corporation or contributors be liable for any direct,
|
||||
// indirect, incidental, special, exemplary, or consequential damages
|
||||
// (including, but not limited to, procurement of substitute goods or services;
|
||||
// loss of use, data, or profits; or business interruption) however caused
|
||||
// and on any theory of liability, whether in contract, strict liability,
|
||||
// or tort (including negligence or otherwise) arising in any way out of
|
||||
// the use of this software, even if advised of the possibility of such damage.
|
||||
//
|
||||
// Authors:
|
||||
// * Ozan Tonkal, ozantonkal@gmail.com
|
||||
// * Anatoly Baksheev, Itseez Inc. myname.mysurname <> mycompany.com
|
||||
//
|
||||
//M*/
|
||||
|
||||
#include "precomp.hpp"
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////
|
||||
cv::viz::Viz3d::VizImpl::VizImpl(const String &name) : spin_once_state_(false),
|
||||
window_position_(Vec2i(std::numeric_limits<int>::min())), widget_actor_map_(new WidgetActorMap)
|
||||
{
|
||||
renderer_ = vtkSmartPointer<vtkRenderer>::New();
|
||||
window_name_ = VizStorage::generateWindowName(name);
|
||||
|
||||
// Create render window
|
||||
window_ = vtkSmartPointer<vtkRenderWindow>::New();
|
||||
int * sz = window_->GetScreenSize();
|
||||
if (sz)
|
||||
{
|
||||
cv::Vec2i window_size = cv::Vec2i(sz) / 2;
|
||||
window_->SetSize(window_size.val);
|
||||
}
|
||||
else
|
||||
{
|
||||
int new_sz[2] = { 640, 480 };
|
||||
window_->SetSize(new_sz);
|
||||
}
|
||||
window_->AddRenderer(renderer_);
|
||||
|
||||
// Create the interactor style
|
||||
style_ = vtkSmartPointer<vtkVizInteractorStyle>::New();
|
||||
style_->setWidgetActorMap(widget_actor_map_);
|
||||
style_->UseTimersOn();
|
||||
|
||||
timer_callback_ = vtkSmartPointer<TimerCallback>::New();
|
||||
exit_callback_ = vtkSmartPointer<ExitCallback>::New();
|
||||
exit_callback_->viz = this;
|
||||
|
||||
offScreenMode_ = false;
|
||||
|
||||
setBackgroundMeshLab();
|
||||
}
|
||||
|
||||
cv::viz::Viz3d::VizImpl::~VizImpl() { close(); }
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////
|
||||
void cv::viz::Viz3d::VizImpl::TimerCallback::Execute(vtkObject* caller, unsigned long event_id, void* cookie)
|
||||
{
|
||||
if (event_id == vtkCommand::TimerEvent && timer_id == *reinterpret_cast<int*>(cookie))
|
||||
{
|
||||
vtkSmartPointer<vtkRenderWindowInteractor> interactor = vtkRenderWindowInteractor::SafeDownCast(caller);
|
||||
interactor->TerminateApp();
|
||||
}
|
||||
}
|
||||
|
||||
void cv::viz::Viz3d::VizImpl::ExitCallback::Execute(vtkObject*, unsigned long event_id, void*)
|
||||
{
|
||||
if (event_id == vtkCommand::ExitEvent && viz->interactor_)
|
||||
{
|
||||
viz->interactor_->TerminateApp();
|
||||
viz->interactor_ = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
bool cv::viz::Viz3d::VizImpl::wasStopped() const
|
||||
{
|
||||
bool stopped = spin_once_state_ ? interactor_ == 0 : false;
|
||||
spin_once_state_ &= !stopped;
|
||||
return stopped;
|
||||
}
|
||||
|
||||
void cv::viz::Viz3d::VizImpl::close()
|
||||
{
|
||||
if (!interactor_)
|
||||
return;
|
||||
interactor_->GetRenderWindow()->Finalize();
|
||||
interactor_->TerminateApp(); // This tends to close the window...
|
||||
interactor_ = 0;
|
||||
}
|
||||
|
||||
void cv::viz::Viz3d::VizImpl::recreateRenderWindow()
|
||||
{
|
||||
#if !defined _MSC_VER && !defined __APPLE__
|
||||
//recreating is workaround for Ubuntu -- a crash in x-server
|
||||
Vec2i window_size(window_->GetSize());
|
||||
int fullscreen = window_->GetFullScreen();
|
||||
|
||||
window_->Finalize();
|
||||
window_ = vtkSmartPointer<vtkRenderWindow>::New();
|
||||
if (window_position_[0] != std::numeric_limits<int>::min()) //also workaround
|
||||
window_->SetPosition(window_position_.val);
|
||||
|
||||
window_->SetSize(window_size.val);
|
||||
window_->SetFullScreen(fullscreen);
|
||||
window_->AddRenderer(renderer_);
|
||||
#endif
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////
|
||||
void cv::viz::Viz3d::VizImpl::spin()
|
||||
{
|
||||
recreateRenderWindow();
|
||||
#if defined __APPLE__
|
||||
interactor_ = vtkCocoaRenderWindowInteractorNew();
|
||||
#else
|
||||
interactor_ = vtkSmartPointer<vtkRenderWindowInteractor>::New();
|
||||
#endif
|
||||
interactor_->SetRenderWindow(window_);
|
||||
interactor_->SetInteractorStyle(style_);
|
||||
window_->AlphaBitPlanesOff();
|
||||
window_->PointSmoothingOff();
|
||||
window_->LineSmoothingOff();
|
||||
window_->PolygonSmoothingOff();
|
||||
window_->SwapBuffersOn();
|
||||
window_->SetStereoTypeToAnaglyph();
|
||||
window_->Render();
|
||||
window_->SetWindowName(window_name_.c_str());
|
||||
interactor_->Start();
|
||||
interactor_ = 0;
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////
|
||||
void cv::viz::Viz3d::VizImpl::spinOnce(int time, bool force_redraw)
|
||||
{
|
||||
if (interactor_ == 0)
|
||||
{
|
||||
spin_once_state_ = true;
|
||||
recreateRenderWindow();
|
||||
#if defined __APPLE__
|
||||
interactor_ = vtkCocoaRenderWindowInteractorNew();
|
||||
#else
|
||||
interactor_ = vtkSmartPointer<vtkRenderWindowInteractor>::New();
|
||||
#endif
|
||||
interactor_->SetRenderWindow(window_);
|
||||
interactor_->SetInteractorStyle(style_);
|
||||
interactor_->AddObserver(vtkCommand::TimerEvent, timer_callback_);
|
||||
interactor_->AddObserver(vtkCommand::ExitEvent, exit_callback_);
|
||||
window_->AlphaBitPlanesOff();
|
||||
window_->PointSmoothingOff();
|
||||
window_->LineSmoothingOff();
|
||||
window_->PolygonSmoothingOff();
|
||||
window_->SwapBuffersOn();
|
||||
window_->SetStereoTypeToAnaglyph();
|
||||
window_->Render();
|
||||
window_->SetWindowName(window_name_.c_str());
|
||||
}
|
||||
|
||||
vtkSmartPointer<vtkRenderWindowInteractor> local = interactor_;
|
||||
|
||||
if (force_redraw)
|
||||
local->Render();
|
||||
|
||||
timer_callback_->timer_id = local->CreateRepeatingTimer(std::max(1, time));
|
||||
local->Start();
|
||||
local->DestroyTimer(timer_callback_->timer_id);
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////
|
||||
void cv::viz::Viz3d::VizImpl::setOffScreenRendering()
|
||||
{
|
||||
window_->SetOffScreenRendering(1);
|
||||
offScreenMode_ = true;
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////
|
||||
void cv::viz::Viz3d::VizImpl::removeAllLights()
|
||||
{
|
||||
renderer_->RemoveAllLights();
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////
|
||||
void cv::viz::Viz3d::VizImpl::addLight(Vec3d position, Vec3d focalPoint, const Color &color, const Color &diffuseColor,
|
||||
const Color &ambientColor, const Color &specularColor)
|
||||
{
|
||||
Color color_ = vtkcolor(color);
|
||||
Color diffuseColor_ = vtkcolor(diffuseColor);
|
||||
Color ambientColor_ = vtkcolor(ambientColor);
|
||||
Color specularColor_ = vtkcolor(specularColor);
|
||||
|
||||
vtkSmartPointer<vtkLight> light = vtkSmartPointer<vtkLight>::New();
|
||||
light->SetPosition(position.val);
|
||||
light->SetFocalPoint(focalPoint.val);
|
||||
light->SetColor(color_.val);
|
||||
light->SetDiffuseColor(diffuseColor_.val);
|
||||
light->SetAmbientColor(ambientColor_.val);
|
||||
light->SetSpecularColor(specularColor_.val);
|
||||
|
||||
renderer_->AddLight(light);
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////
|
||||
void cv::viz::Viz3d::VizImpl::showWidget(const String &id, const Widget &widget, const Affine3d &pose)
|
||||
{
|
||||
WidgetActorMap::iterator wam_itr = widget_actor_map_->find(id);
|
||||
bool exists = wam_itr != widget_actor_map_->end();
|
||||
if (exists)
|
||||
{
|
||||
// Remove it if it exists and add it again
|
||||
removeActorFromRenderer(wam_itr->second);
|
||||
}
|
||||
// Get the actor and set the user matrix
|
||||
vtkProp3D *actor = vtkProp3D::SafeDownCast(WidgetAccessor::getProp(widget));
|
||||
if (actor)
|
||||
{
|
||||
// If the actor is 3D, apply pose
|
||||
vtkSmartPointer<vtkMatrix4x4> matrix = vtkmatrix(pose.matrix);
|
||||
actor->SetUserMatrix(matrix);
|
||||
actor->Modified();
|
||||
}
|
||||
// If the actor is a vtkFollower, then it should always face the camera
|
||||
vtkFollower *follower = vtkFollower::SafeDownCast(actor);
|
||||
if (follower)
|
||||
{
|
||||
follower->SetCamera(renderer_->GetActiveCamera());
|
||||
}
|
||||
|
||||
renderer_->AddActor(WidgetAccessor::getProp(widget));
|
||||
(*widget_actor_map_)[id] = WidgetAccessor::getProp(widget);
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////
|
||||
void cv::viz::Viz3d::VizImpl::removeWidget(const String &id)
|
||||
{
|
||||
WidgetActorMap::iterator wam_itr = widget_actor_map_->find(id);
|
||||
bool exists = wam_itr != widget_actor_map_->end();
|
||||
CV_Assert("Widget does not exist." && exists);
|
||||
CV_Assert("Widget could not be removed." && removeActorFromRenderer(wam_itr->second));
|
||||
widget_actor_map_->erase(wam_itr);
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////
|
||||
cv::viz::Widget cv::viz::Viz3d::VizImpl::getWidget(const String &id) const
|
||||
{
|
||||
WidgetActorMap::const_iterator wam_itr = widget_actor_map_->find(id);
|
||||
bool exists = wam_itr != widget_actor_map_->end();
|
||||
CV_Assert("Widget does not exist." && exists);
|
||||
|
||||
Widget widget;
|
||||
WidgetAccessor::setProp(widget, wam_itr->second);
|
||||
return widget;
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////
|
||||
void cv::viz::Viz3d::VizImpl::setWidgetPose(const String &id, const Affine3d &pose)
|
||||
{
|
||||
WidgetActorMap::iterator wam_itr = widget_actor_map_->find(id);
|
||||
bool exists = wam_itr != widget_actor_map_->end();
|
||||
CV_Assert("Widget does not exist." && exists);
|
||||
|
||||
vtkProp3D *actor = vtkProp3D::SafeDownCast(wam_itr->second);
|
||||
CV_Assert("Widget is not 3D." && actor);
|
||||
|
||||
vtkSmartPointer<vtkMatrix4x4> matrix = vtkmatrix(pose.matrix);
|
||||
actor->SetUserMatrix(matrix);
|
||||
actor->Modified();
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////
|
||||
void cv::viz::Viz3d::VizImpl::updateWidgetPose(const String &id, const Affine3d &pose)
|
||||
{
|
||||
WidgetActorMap::iterator wam_itr = widget_actor_map_->find(id);
|
||||
bool exists = wam_itr != widget_actor_map_->end();
|
||||
CV_Assert("Widget does not exist." && exists);
|
||||
|
||||
vtkProp3D *actor = vtkProp3D::SafeDownCast(wam_itr->second);
|
||||
CV_Assert("Widget is not 3D." && actor);
|
||||
|
||||
vtkSmartPointer<vtkMatrix4x4> matrix = actor->GetUserMatrix();
|
||||
if (!matrix)
|
||||
{
|
||||
setWidgetPose(id, pose);
|
||||
return ;
|
||||
}
|
||||
Affine3d updated_pose = pose * Affine3d(*matrix->Element);
|
||||
matrix = vtkmatrix(updated_pose.matrix);
|
||||
|
||||
actor->SetUserMatrix(matrix);
|
||||
actor->Modified();
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////
|
||||
cv::Affine3d cv::viz::Viz3d::VizImpl::getWidgetPose(const String &id) const
|
||||
{
|
||||
WidgetActorMap::const_iterator wam_itr = widget_actor_map_->find(id);
|
||||
bool exists = wam_itr != widget_actor_map_->end();
|
||||
CV_Assert("Widget does not exist." && exists);
|
||||
|
||||
vtkProp3D *actor = vtkProp3D::SafeDownCast(wam_itr->second);
|
||||
CV_Assert("Widget is not 3D." && actor);
|
||||
|
||||
return Affine3d(*actor->GetUserMatrix()->Element);
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////
|
||||
void cv::viz::Viz3d::VizImpl::saveScreenshot(const String &file) { style_->saveScreenshot(file.c_str()); }
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////
|
||||
cv::Mat cv::viz::Viz3d::VizImpl::getScreenshot() const
|
||||
{
|
||||
vtkSmartPointer<vtkWindowToImageFilter> windowToImageFilter =
|
||||
vtkSmartPointer<vtkWindowToImageFilter>::New();
|
||||
windowToImageFilter->SetInput(window_);
|
||||
windowToImageFilter->ReadFrontBufferOff(); // read from the back buffer
|
||||
windowToImageFilter->Update();
|
||||
|
||||
vtkImageData *resultImage = windowToImageFilter->GetOutput();
|
||||
int * dim = resultImage->GetDimensions();
|
||||
cv::Mat image(dim[1], dim[0], CV_8UC3);
|
||||
|
||||
Vec3b* dptr = reinterpret_cast<Vec3b*>(resultImage->GetScalarPointer());
|
||||
size_t elem_step = resultImage->GetIncrements()[1]/sizeof(Vec3b);
|
||||
|
||||
for (int y = 0; y < image.rows; ++y)
|
||||
{
|
||||
const Vec3b* drow = dptr + elem_step * y;
|
||||
unsigned char *srow = image.ptr<unsigned char>(image.rows - y - 1);
|
||||
for (int x = 0; x < image.cols; ++x, srow += image.channels())
|
||||
{
|
||||
srow[0] = drow[x][2];
|
||||
srow[1] = drow[x][1];
|
||||
srow[2] = drow[x][0];
|
||||
}
|
||||
}
|
||||
|
||||
resultImage = 0;
|
||||
|
||||
return image;
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////
|
||||
void cv::viz::Viz3d::VizImpl::registerMouseCallback(MouseCallback callback, void* cookie)
|
||||
{ style_->registerMouseCallback(callback, cookie); }
|
||||
|
||||
void cv::viz::Viz3d::VizImpl::registerKeyboardCallback(KeyboardCallback callback, void* cookie)
|
||||
{ style_->registerKeyboardCallback(callback, cookie); }
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////
|
||||
void cv::viz::Viz3d::VizImpl::removeAllWidgets()
|
||||
{
|
||||
widget_actor_map_->clear();
|
||||
renderer_->RemoveAllViewProps();
|
||||
}
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////
|
||||
void cv::viz::Viz3d::VizImpl::showImage(InputArray image, const Size& window_size)
|
||||
{
|
||||
removeAllWidgets();
|
||||
if (window_size.width > 0 && window_size.height > 0)
|
||||
setWindowSize(window_size);
|
||||
|
||||
showWidget("showImage", WImageOverlay(image, Rect(Point(0,0), getWindowSize())));
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////
|
||||
bool cv::viz::Viz3d::VizImpl::removeActorFromRenderer(vtkSmartPointer<vtkProp> actor)
|
||||
{
|
||||
vtkPropCollection* actors = renderer_->GetViewProps();
|
||||
actors->InitTraversal();
|
||||
vtkProp* current_actor = NULL;
|
||||
while ((current_actor = actors->GetNextProp()) != NULL)
|
||||
if (current_actor == actor)
|
||||
{
|
||||
renderer_->RemoveActor(actor);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////
|
||||
void cv::viz::Viz3d::VizImpl::setBackgroundColor(const Color& color, const Color& color2)
|
||||
{
|
||||
Color c = vtkcolor(color), c2 = vtkcolor(color2);
|
||||
bool gradient = color2[0] >= 0 && color2[1] >= 0 && color2[2] >= 0;
|
||||
|
||||
if (gradient)
|
||||
{
|
||||
renderer_->SetBackground(c2.val);
|
||||
renderer_->SetBackground2(c.val);
|
||||
renderer_->GradientBackgroundOn();
|
||||
}
|
||||
else
|
||||
{
|
||||
renderer_->SetBackground(c.val);
|
||||
renderer_->GradientBackgroundOff();
|
||||
}
|
||||
}
|
||||
|
||||
void cv::viz::Viz3d::VizImpl::setBackgroundMeshLab()
|
||||
{ setBackgroundColor(Color(2, 1, 1), Color(240, 120, 120)); }
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////
|
||||
void cv::viz::Viz3d::VizImpl::setBackgroundTexture(InputArray image)
|
||||
{
|
||||
if (image.empty())
|
||||
{
|
||||
renderer_->SetBackgroundTexture(0);
|
||||
renderer_->TexturedBackgroundOff();
|
||||
return;
|
||||
}
|
||||
|
||||
vtkSmartPointer<vtkImageMatSource> source = vtkSmartPointer<vtkImageMatSource>::New();
|
||||
source->SetImage(image);
|
||||
|
||||
vtkSmartPointer<vtkImageFlip> image_flip = vtkSmartPointer<vtkImageFlip>::New();
|
||||
image_flip->SetFilteredAxis(1); // Vertical flip
|
||||
image_flip->SetInputConnection(source->GetOutputPort());
|
||||
|
||||
vtkSmartPointer<vtkTexture> texture = vtkSmartPointer<vtkTexture>::New();
|
||||
texture->SetInputConnection(image_flip->GetOutputPort());
|
||||
//texture->Update();
|
||||
|
||||
renderer_->SetBackgroundTexture(texture);
|
||||
renderer_->TexturedBackgroundOn();
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////
|
||||
void cv::viz::Viz3d::VizImpl::setCamera(const Camera &camera)
|
||||
{
|
||||
vtkSmartPointer<vtkCamera> active_camera = renderer_->GetActiveCamera();
|
||||
|
||||
// Set the intrinsic parameters of the camera
|
||||
window_->SetSize(camera.getWindowSize().width, camera.getWindowSize().height);
|
||||
double aspect_ratio = static_cast<double>(camera.getWindowSize().width)/static_cast<double>(camera.getWindowSize().height);
|
||||
|
||||
Matx44d proj_mat;
|
||||
camera.computeProjectionMatrix(proj_mat);
|
||||
|
||||
// Use the intrinsic parameters of the camera to simulate more realistically
|
||||
vtkSmartPointer<vtkMatrix4x4> vtk_matrix = active_camera->GetProjectionTransformMatrix(aspect_ratio, -1.0, 1.0);
|
||||
Matx44d old_proj_mat(*vtk_matrix->Element);
|
||||
|
||||
// This is a hack around not being able to set Projection Matrix
|
||||
vtkSmartPointer<vtkTransform> transform = vtkSmartPointer<vtkTransform>::New();
|
||||
transform->SetMatrix(vtkmatrix(proj_mat * old_proj_mat.inv()));
|
||||
active_camera->SetUserTransform(transform);
|
||||
|
||||
renderer_->ResetCameraClippingRange();
|
||||
renderer_->Render();
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////
|
||||
cv::viz::Camera cv::viz::Viz3d::VizImpl::getCamera() const
|
||||
{
|
||||
vtkSmartPointer<vtkCamera> active_camera = renderer_->GetActiveCamera();
|
||||
|
||||
Size window_size(renderer_->GetRenderWindow()->GetSize()[0],
|
||||
renderer_->GetRenderWindow()->GetSize()[1]);
|
||||
double aspect_ratio = window_size.width / (double)window_size.height;
|
||||
|
||||
vtkSmartPointer<vtkMatrix4x4> proj_matrix = active_camera->GetProjectionTransformMatrix(aspect_ratio, -1.0f, 1.0f);
|
||||
return Camera(Matx44d(*proj_matrix->Element), window_size);
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////
|
||||
void cv::viz::Viz3d::VizImpl::setViewerPose(const Affine3d &pose)
|
||||
{
|
||||
vtkCamera& camera = *renderer_->GetActiveCamera();
|
||||
|
||||
// Position = extrinsic translation
|
||||
cv::Vec3d pos_vec = pose.translation();
|
||||
|
||||
// Rotate the view vector
|
||||
cv::Matx33d rotation = pose.rotation();
|
||||
cv::Vec3d y_axis(0.0, -1.0, 0.0); // In Computer Vision Camera Y-axis is oriented down
|
||||
cv::Vec3d up_vec(rotation * y_axis);
|
||||
|
||||
// Compute the new focal point
|
||||
cv::Vec3d z_axis(0.0, 0.0, 1.0);
|
||||
cv::Vec3d focal_vec = pose * z_axis;
|
||||
|
||||
camera.SetPosition(pos_vec.val);
|
||||
camera.SetFocalPoint(focal_vec.val);
|
||||
camera.SetViewUp(up_vec.val);
|
||||
|
||||
renderer_->ResetCameraClippingRange();
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////
|
||||
cv::Affine3d cv::viz::Viz3d::VizImpl::getViewerPose() const
|
||||
{
|
||||
vtkCamera& camera = *renderer_->GetActiveCamera();
|
||||
|
||||
Vec3d pos(camera.GetPosition());
|
||||
Vec3d view_up(camera.GetViewUp());
|
||||
Vec3d focal(camera.GetFocalPoint());
|
||||
|
||||
Vec3d y_axis = normalized(-view_up); // In Computer Vision Camera Y-axis is oriented down
|
||||
Vec3d z_axis = normalized(focal - pos);
|
||||
Vec3d x_axis = normalized(y_axis.cross(z_axis));
|
||||
|
||||
return makeTransformToGlobal(x_axis, y_axis, z_axis, pos);
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////
|
||||
void cv::viz::Viz3d::VizImpl::convertToWindowCoordinates(const Point3d &pt, Point3d &window_coord)
|
||||
{
|
||||
Vec3d window_pt;
|
||||
vtkInteractorObserver::ComputeWorldToDisplay(renderer_, pt.x, pt.y, pt.z, window_pt.val);
|
||||
window_coord = window_pt;
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////
|
||||
void cv::viz::Viz3d::VizImpl::converTo3DRay(const Point3d &window_coord, Point3d &origin, Vec3d &direction)
|
||||
{
|
||||
Vec4d world_pt;
|
||||
vtkInteractorObserver::ComputeDisplayToWorld(renderer_, window_coord.x, window_coord.y, window_coord.z, world_pt.val);
|
||||
Vec3d cam_pos(renderer_->GetActiveCamera()->GetPosition());
|
||||
origin = cam_pos;
|
||||
direction = normalize(Vec3d(world_pt.val) - cam_pos);
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////
|
||||
void cv::viz::Viz3d::VizImpl::resetCameraViewpoint(const String &id)
|
||||
{
|
||||
vtkSmartPointer<vtkMatrix4x4> camera_pose;
|
||||
static WidgetActorMap::iterator it = widget_actor_map_->find(id);
|
||||
if (it != widget_actor_map_->end())
|
||||
{
|
||||
vtkProp3D *actor = vtkProp3D::SafeDownCast(it->second);
|
||||
CV_Assert("Widget is not 3D." && actor);
|
||||
camera_pose = actor->GetUserMatrix();
|
||||
}
|
||||
else
|
||||
return;
|
||||
|
||||
// Prevent a segfault
|
||||
if (!camera_pose) return;
|
||||
|
||||
vtkSmartPointer<vtkCamera> cam = renderer_->GetActiveCamera();
|
||||
cam->SetPosition(camera_pose->GetElement(0, 3),
|
||||
camera_pose->GetElement(1, 3),
|
||||
camera_pose->GetElement(2, 3));
|
||||
|
||||
cam->SetFocalPoint(camera_pose->GetElement(0, 3) - camera_pose->GetElement(0, 2),
|
||||
camera_pose->GetElement(1, 3) - camera_pose->GetElement(1, 2),
|
||||
camera_pose->GetElement(2, 3) - camera_pose->GetElement(2, 2));
|
||||
|
||||
cam->SetViewUp(camera_pose->GetElement(0, 1),
|
||||
camera_pose->GetElement(1, 1),
|
||||
camera_pose->GetElement(2, 1));
|
||||
|
||||
renderer_->SetActiveCamera(cam);
|
||||
renderer_->ResetCameraClippingRange();
|
||||
renderer_->ResetCamera();
|
||||
renderer_->Render();
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////
|
||||
void cv::viz::Viz3d::VizImpl::resetCamera()
|
||||
{
|
||||
renderer_->ResetCamera();
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////
|
||||
void cv::viz::Viz3d::VizImpl::setRepresentation(int representation)
|
||||
{
|
||||
vtkActorCollection * actors = renderer_->GetActors();
|
||||
actors->InitTraversal();
|
||||
vtkActor * actor;
|
||||
switch (representation)
|
||||
{
|
||||
case REPRESENTATION_POINTS:
|
||||
{
|
||||
while ((actor = actors->GetNextActor()) != NULL)
|
||||
actor->GetProperty()->SetRepresentationToPoints();
|
||||
break;
|
||||
}
|
||||
case REPRESENTATION_SURFACE:
|
||||
{
|
||||
while ((actor = actors->GetNextActor()) != NULL)
|
||||
actor->GetProperty()->SetRepresentationToSurface();
|
||||
break;
|
||||
}
|
||||
case REPRESENTATION_WIREFRAME:
|
||||
{
|
||||
while ((actor = actors->GetNextActor()) != NULL)
|
||||
actor->GetProperty()->SetRepresentationToWireframe();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////
|
||||
cv::String cv::viz::Viz3d::VizImpl::getWindowName() const { return window_name_; }
|
||||
void cv::viz::Viz3d::VizImpl::setFullScreen(bool mode) { window_->SetFullScreen(mode); }
|
||||
void cv::viz::Viz3d::VizImpl::setWindowPosition(const Point& position) { window_position_ = position; window_->SetPosition(position.x, position.y); }
|
||||
void cv::viz::Viz3d::VizImpl::setWindowSize(const Size& window_size) { window_->SetSize(window_size.width, window_size.height); }
|
||||
cv::Size cv::viz::Viz3d::VizImpl::getWindowSize() const { return Size(Point(Vec2i(window_->GetSize()))); }
|
|
@ -0,0 +1,146 @@
|
|||
/*M///////////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
|
||||
//
|
||||
// By downloading, copying, installing or using the software you agree to this license.
|
||||
// If you do not agree to this license, do not download, install,
|
||||
// copy or use the software.
|
||||
//
|
||||
//
|
||||
// License Agreement
|
||||
// For Open Source Computer Vision Library
|
||||
//
|
||||
// Copyright (C) 2013, OpenCV Foundation, all rights reserved.
|
||||
// Third party copyrights are property of their respective owners.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without modification,
|
||||
// are permitted provided that the following conditions are met:
|
||||
//
|
||||
// * Redistribution's of source code must retain the above copyright notice,
|
||||
// this list of conditions and the following disclaimer.
|
||||
//
|
||||
// * Redistribution's in binary form must reproduce the above copyright notice,
|
||||
// this list of conditions and the following disclaimer in the documentation
|
||||
// and/or other materials provided with the distribution.
|
||||
//
|
||||
// * The name of the copyright holders may not be used to endorse or promote products
|
||||
// derived from this software without specific prior written permission.
|
||||
//
|
||||
// This software is provided by the copyright holders and contributors "as is" and
|
||||
// any express or implied warranties, including, but not limited to, the implied
|
||||
// warranties of merchantability and fitness for a particular purpose are disclaimed.
|
||||
// In no event shall the Intel Corporation or contributors be liable for any direct,
|
||||
// indirect, incidental, special, exemplary, or consequential damages
|
||||
// (including, but not limited to, procurement of substitute goods or services;
|
||||
// loss of use, data, or profits; or business interruption) however caused
|
||||
// and on any theory of liability, whether in contract, strict liability,
|
||||
// or tort (including negligence or otherwise) arising in any way out of
|
||||
// the use of this software, even if advised of the possibility of such damage.
|
||||
//
|
||||
// Authors:
|
||||
// * Ozan Tonkal, ozantonkal@gmail.com
|
||||
// * Anatoly Baksheev, Itseez Inc. myname.mysurname <> mycompany.com
|
||||
//
|
||||
//M*/
|
||||
|
||||
#ifndef __OPENCV_VIZ_VIZ3D_IMPL_HPP__
|
||||
#define __OPENCV_VIZ_VIZ3D_IMPL_HPP__
|
||||
|
||||
struct cv::viz::Viz3d::VizImpl
|
||||
{
|
||||
public:
|
||||
typedef Viz3d::KeyboardCallback KeyboardCallback;
|
||||
typedef Viz3d::MouseCallback MouseCallback;
|
||||
|
||||
int ref_counter;
|
||||
|
||||
VizImpl(const String &name);
|
||||
virtual ~VizImpl();
|
||||
|
||||
bool wasStopped() const;
|
||||
void close();
|
||||
|
||||
void spin();
|
||||
void spinOnce(int time = 1, bool force_redraw = false);
|
||||
void setOffScreenRendering();
|
||||
|
||||
void removeAllLights();
|
||||
void addLight(Vec3d position, Vec3d focalPoint, const Color &color, const Color &diffuseColor,
|
||||
const Color &ambientColor, const Color &specularColor);
|
||||
|
||||
void showWidget(const String &id, const Widget &widget, const Affine3d &pose = Affine3d::Identity());
|
||||
void removeWidget(const String &id);
|
||||
Widget getWidget(const String &id) const;
|
||||
void removeAllWidgets();
|
||||
|
||||
void showImage(InputArray image, const Size& window_size);
|
||||
|
||||
void setWidgetPose(const String &id, const Affine3d &pose);
|
||||
void updateWidgetPose(const String &id, const Affine3d &pose);
|
||||
Affine3d getWidgetPose(const String &id) const;
|
||||
|
||||
void setRepresentation(int representation);
|
||||
|
||||
void setCamera(const Camera &camera);
|
||||
Camera getCamera() const;
|
||||
|
||||
/** \brief Reset the camera to a given widget */
|
||||
void resetCameraViewpoint(const String& id);
|
||||
void resetCamera();
|
||||
|
||||
void setViewerPose(const Affine3d &pose);
|
||||
Affine3d getViewerPose() const;
|
||||
|
||||
void convertToWindowCoordinates(const Point3d &pt, Point3d &window_coord);
|
||||
void converTo3DRay(const Point3d &window_coord, Point3d &origin, Vec3d &direction);
|
||||
|
||||
Mat getScreenshot() const;
|
||||
void saveScreenshot(const String &file);
|
||||
void setWindowPosition(const Point& position);
|
||||
Size getWindowSize() const;
|
||||
void setWindowSize(const Size& window_size);
|
||||
void setFullScreen(bool mode);
|
||||
String getWindowName() const;
|
||||
void setBackgroundColor(const Color& color, const Color& color2);
|
||||
void setBackgroundTexture(InputArray image);
|
||||
void setBackgroundMeshLab();
|
||||
|
||||
void registerKeyboardCallback(KeyboardCallback callback, void* cookie = 0);
|
||||
void registerMouseCallback(MouseCallback callback, void* cookie = 0);
|
||||
|
||||
private:
|
||||
struct TimerCallback : public vtkCommand
|
||||
{
|
||||
static TimerCallback* New() { return new TimerCallback; }
|
||||
virtual void Execute(vtkObject* caller, unsigned long event_id, void* cookie);
|
||||
int timer_id;
|
||||
};
|
||||
|
||||
struct ExitCallback : public vtkCommand
|
||||
{
|
||||
static ExitCallback* New() { return new ExitCallback; }
|
||||
virtual void Execute(vtkObject*, unsigned long event_id, void*);
|
||||
VizImpl* viz;
|
||||
};
|
||||
|
||||
mutable bool spin_once_state_;
|
||||
vtkSmartPointer<vtkRenderWindowInteractor> interactor_;
|
||||
|
||||
vtkSmartPointer<vtkRenderWindow> window_;
|
||||
String window_name_;
|
||||
Vec2i window_position_;
|
||||
|
||||
vtkSmartPointer<TimerCallback> timer_callback_;
|
||||
vtkSmartPointer<ExitCallback> exit_callback_;
|
||||
|
||||
vtkSmartPointer<vtkRenderer> renderer_;
|
||||
vtkSmartPointer<vtkVizInteractorStyle> style_;
|
||||
Ptr<WidgetActorMap> widget_actor_map_;
|
||||
|
||||
bool offScreenMode_;
|
||||
|
||||
bool removeActorFromRenderer(vtkSmartPointer<vtkProp> actor);
|
||||
void recreateRenderWindow();
|
||||
};
|
||||
|
||||
#endif
|
|
@ -0,0 +1,174 @@
|
|||
/*M///////////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
|
||||
//
|
||||
// By downloading, copying, installing or using the software you agree to this license.
|
||||
// If you do not agree to this license, do not download, install,
|
||||
// copy or use the software.
|
||||
//
|
||||
//
|
||||
// License Agreement
|
||||
// For Open Source Computer Vision Library
|
||||
//
|
||||
// Copyright (C) 2013, OpenCV Foundation, all rights reserved.
|
||||
// Third party copyrights are property of their respective owners.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without modification,
|
||||
// are permitted provided that the following conditions are met:
|
||||
//
|
||||
// * Redistribution's of source code must retain the above copyright notice,
|
||||
// this list of conditions and the following disclaimer.
|
||||
//
|
||||
// * Redistribution's in binary form must reproduce the above copyright notice,
|
||||
// this list of conditions and the following disclaimer in the documentation
|
||||
// and/or other materials provided with the distribution.
|
||||
//
|
||||
// * The name of the copyright holders may not be used to endorse or promote products
|
||||
// derived from this software without specific prior written permission.
|
||||
//
|
||||
// This software is provided by the copyright holders and contributors "as is" and
|
||||
// any express or implied warranties, including, but not limited to, the implied
|
||||
// warranties of merchantability and fitness for a particular purpose are disclaimed.
|
||||
// In no event shall the Intel Corporation or contributors be liable for any direct,
|
||||
// indirect, incidental, special, exemplary, or consequential damages
|
||||
// (including, but not limited to, procurement of substitute goods or services;
|
||||
// loss of use, data, or profits; or business interruption) however caused
|
||||
// and on any theory of liability, whether in contract, strict liability,
|
||||
// or tort (including negligence or otherwise) arising in any way out of
|
||||
// the use of this software, even if advised of the possibility of such damage.
|
||||
//
|
||||
// Authors:
|
||||
// * Anatoly Baksheev, Itseez Inc. myname.mysurname <> mycompany.com
|
||||
//
|
||||
//M*/
|
||||
|
||||
#include "../precomp.hpp"
|
||||
|
||||
namespace cv { namespace viz
|
||||
{
|
||||
vtkStandardNewMacro(vtkCloudMatSink);
|
||||
}}
|
||||
|
||||
cv::viz::vtkCloudMatSink::vtkCloudMatSink() {}
|
||||
cv::viz::vtkCloudMatSink::~vtkCloudMatSink() {}
|
||||
|
||||
void cv::viz::vtkCloudMatSink::SetOutput(OutputArray _cloud, OutputArray _colors, OutputArray _normals, OutputArray _tcoords)
|
||||
{
|
||||
cloud = _cloud;
|
||||
colors = _colors;
|
||||
normals = _normals;
|
||||
tcoords = _tcoords;
|
||||
}
|
||||
|
||||
void cv::viz::vtkCloudMatSink::WriteData()
|
||||
{
|
||||
vtkPolyData *input = this->GetInput();
|
||||
if (!input)
|
||||
return;
|
||||
|
||||
vtkSmartPointer<vtkPoints> points_Data = input->GetPoints();
|
||||
|
||||
if (cloud.needed() && points_Data)
|
||||
{
|
||||
int vtktype = points_Data->GetDataType();
|
||||
CV_Assert(vtktype == VTK_FLOAT || vtktype == VTK_DOUBLE);
|
||||
|
||||
cloud.create(1, points_Data->GetNumberOfPoints(), vtktype == VTK_FLOAT ? CV_32FC3 : CV_64FC3);
|
||||
Vec3d *ddata = cloud.getMat().ptr<Vec3d>();
|
||||
Vec3f *fdata = cloud.getMat().ptr<Vec3f>();
|
||||
|
||||
if (cloud.depth() == CV_32F)
|
||||
for(size_t i = 0; i < cloud.total(); ++i)
|
||||
*fdata++ = Vec3d(points_Data->GetPoint((vtkIdType)i));
|
||||
|
||||
if (cloud.depth() == CV_64F)
|
||||
for(size_t i = 0; i < cloud.total(); ++i)
|
||||
*ddata++ = Vec3d(points_Data->GetPoint((vtkIdType)i));
|
||||
}
|
||||
else
|
||||
cloud.release();
|
||||
|
||||
vtkSmartPointer<vtkDataArray> scalars_data = input->GetPointData() ? input->GetPointData()->GetScalars() : 0;
|
||||
|
||||
if (colors.needed() && scalars_data)
|
||||
{
|
||||
int channels = scalars_data->GetNumberOfComponents();
|
||||
int vtktype = scalars_data->GetDataType();
|
||||
|
||||
CV_Assert((channels == 3 || channels == 4) && "Only 3- or 4-channel color data support is implemented");
|
||||
CV_Assert(cloud.total() == (size_t)scalars_data->GetNumberOfTuples());
|
||||
|
||||
Mat buffer(cloud.size(), CV_64FC(channels));
|
||||
Vec3d *cptr = buffer.ptr<Vec3d>();
|
||||
for(size_t i = 0; i < buffer.total(); ++i)
|
||||
*cptr++ = Vec3d(scalars_data->GetTuple((vtkIdType)i));
|
||||
|
||||
buffer.convertTo(colors, CV_8U, vtktype == VTK_FLOAT || VTK_FLOAT == VTK_DOUBLE ? 255.0 : 1.0);
|
||||
}
|
||||
else
|
||||
colors.release();
|
||||
|
||||
vtkSmartPointer<vtkDataArray> normals_data = input->GetPointData() ? input->GetPointData()->GetNormals() : 0;
|
||||
|
||||
if (normals.needed() && normals_data)
|
||||
{
|
||||
int channels = normals_data->GetNumberOfComponents();
|
||||
int vtktype = normals_data->GetDataType();
|
||||
|
||||
CV_Assert((vtktype == VTK_FLOAT || VTK_FLOAT == VTK_DOUBLE) && (channels == 3 || channels == 4));
|
||||
CV_Assert(cloud.total() == (size_t)normals_data->GetNumberOfTuples());
|
||||
|
||||
Mat buffer(cloud.size(), CV_64FC(channels));
|
||||
Vec3d *cptr = buffer.ptr<Vec3d>();
|
||||
for(size_t i = 0; i < buffer.total(); ++i)
|
||||
*cptr++ = Vec3d(normals_data->GetTuple((vtkIdType)i));
|
||||
|
||||
buffer.convertTo(normals, vtktype == VTK_FLOAT ? CV_32F : CV_64F);
|
||||
}
|
||||
else
|
||||
normals.release();
|
||||
|
||||
vtkSmartPointer<vtkDataArray> coords_data = input->GetPointData() ? input->GetPointData()->GetTCoords() : 0;
|
||||
|
||||
if (tcoords.needed() && coords_data)
|
||||
{
|
||||
int vtktype = coords_data->GetDataType();
|
||||
|
||||
CV_Assert(vtktype == VTK_FLOAT || VTK_FLOAT == VTK_DOUBLE);
|
||||
CV_Assert(cloud.total() == (size_t)coords_data->GetNumberOfTuples());
|
||||
|
||||
Mat buffer(cloud.size(), CV_64FC2);
|
||||
Vec2d *cptr = buffer.ptr<Vec2d>();
|
||||
for(size_t i = 0; i < buffer.total(); ++i)
|
||||
*cptr++ = Vec2d(coords_data->GetTuple((vtkIdType)i));
|
||||
|
||||
buffer.convertTo(tcoords, vtktype == VTK_FLOAT ? CV_32F : CV_64F);
|
||||
|
||||
}
|
||||
else
|
||||
tcoords.release();
|
||||
}
|
||||
|
||||
void cv::viz::vtkCloudMatSink::PrintSelf(ostream& os, vtkIndent indent)
|
||||
{
|
||||
Superclass::PrintSelf(os, indent);
|
||||
os << indent << "Cloud: " << cloud.needed() << "\n";
|
||||
os << indent << "Colors: " << colors.needed() << "\n";
|
||||
os << indent << "Normals: " << normals.needed() << "\n";
|
||||
}
|
||||
|
||||
int cv::viz::vtkCloudMatSink::FillInputPortInformation(int, vtkInformation *info)
|
||||
{
|
||||
info->Set(vtkAlgorithm::INPUT_REQUIRED_DATA_TYPE(), "vtkPolyData");
|
||||
return 1;
|
||||
}
|
||||
|
||||
vtkPolyData* cv::viz::vtkCloudMatSink::GetInput()
|
||||
{
|
||||
return vtkPolyData::SafeDownCast(this->Superclass::GetInput());
|
||||
}
|
||||
|
||||
vtkPolyData* cv::viz::vtkCloudMatSink::GetInput(int port)
|
||||
{
|
||||
return vtkPolyData::SafeDownCast(this->Superclass::GetInput(port));
|
||||
}
|
|
@ -0,0 +1,88 @@
|
|||
/*M///////////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
|
||||
//
|
||||
// By downloading, copying, installing or using the software you agree to this license.
|
||||
// If you do not agree to this license, do not download, install,
|
||||
// copy or use the software.
|
||||
//
|
||||
//
|
||||
// License Agreement
|
||||
// For Open Source Computer Vision Library
|
||||
//
|
||||
// Copyright (C) 2013, OpenCV Foundation, all rights reserved.
|
||||
// Third party copyrights are property of their respective owners.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without modification,
|
||||
// are permitted provided that the following conditions are met:
|
||||
//
|
||||
// * Redistribution's of source code must retain the above copyright notice,
|
||||
// this list of conditions and the following disclaimer.
|
||||
//
|
||||
// * Redistribution's in binary form must reproduce the above copyright notice,
|
||||
// this list of conditions and the following disclaimer in the documentation
|
||||
// and/or other materials provided with the distribution.
|
||||
//
|
||||
// * The name of the copyright holders may not be used to endorse or promote products
|
||||
// derived from this software without specific prior written permission.
|
||||
//
|
||||
// This software is provided by the copyright holders and contributors "as is" and
|
||||
// any express or implied warranties, including, but not limited to, the implied
|
||||
// warranties of merchantability and fitness for a particular purpose are disclaimed.
|
||||
// In no event shall the Intel Corporation or contributors be liable for any direct,
|
||||
// indirect, incidental, special, exemplary, or consequential damages
|
||||
// (including, but not limited to, procurement of substitute goods or services;
|
||||
// loss of use, data, or profits; or business interruption) however caused
|
||||
// and on any theory of liability, whether in contract, strict liability,
|
||||
// or tort (including negligence or otherwise) arising in any way out of
|
||||
// the use of this software, even if advised of the possibility of such damage.
|
||||
//
|
||||
// Authors:
|
||||
// * Anatoly Baksheev, Itseez Inc. myname.mysurname <> mycompany.com
|
||||
//
|
||||
//M*/
|
||||
|
||||
#ifndef __vtkCloudMatSink_h
|
||||
#define __vtkCloudMatSink_h
|
||||
|
||||
#include <opencv2/core.hpp>
|
||||
#include <vtkWriter.h>
|
||||
|
||||
namespace cv
|
||||
{
|
||||
namespace viz
|
||||
{
|
||||
class vtkCloudMatSink : public vtkWriter
|
||||
{
|
||||
public:
|
||||
static vtkCloudMatSink *New();
|
||||
vtkTypeMacro(vtkCloudMatSink,vtkWriter)
|
||||
void PrintSelf(ostream& os, vtkIndent indent);
|
||||
|
||||
void SetOutput(OutputArray cloud, OutputArray colors = noArray(), OutputArray normals = noArray(), OutputArray tcoords = noArray());
|
||||
|
||||
// Description:
|
||||
// Get the input to this writer.
|
||||
vtkPolyData* GetInput();
|
||||
vtkPolyData* GetInput(int port);
|
||||
|
||||
protected:
|
||||
vtkCloudMatSink();
|
||||
~vtkCloudMatSink();
|
||||
|
||||
void WriteData();
|
||||
int FillInputPortInformation(int port, vtkInformation *info);
|
||||
|
||||
_OutputArray cloud; //!< point coordinates of type CV_32FC3 or CV_64FC3 with only 1 row
|
||||
_OutputArray colors; //!< point color of type CV_8UC3 or CV_8UC4 with only 1 row
|
||||
_OutputArray normals; //!< point normal of type CV_32FC3, CV_32FC4, CV_64FC3 or CV_64FC4 with only 1 row
|
||||
_OutputArray tcoords; //!< texture coordinates of type CV_32FC2 or CV_64FC2 with only 1 row
|
||||
|
||||
private:
|
||||
vtkCloudMatSink(const vtkCloudMatSink&); // Not implemented.
|
||||
void operator=(const vtkCloudMatSink&); // Not implemented.
|
||||
};
|
||||
} // end namespace viz
|
||||
} // end namespace cv
|
||||
|
||||
#endif
|
|
@ -0,0 +1,286 @@
|
|||
/*M///////////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
|
||||
//
|
||||
// By downloading, copying, installing or using the software you agree to this license.
|
||||
// If you do not agree to this license, do not download, install,
|
||||
// copy or use the software.
|
||||
//
|
||||
//
|
||||
// License Agreement
|
||||
// For Open Source Computer Vision Library
|
||||
//
|
||||
// Copyright (C) 2013, OpenCV Foundation, all rights reserved.
|
||||
// Third party copyrights are property of their respective owners.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without modification,
|
||||
// are permitted provided that the following conditions are met:
|
||||
//
|
||||
// * Redistribution's of source code must retain the above copyright notice,
|
||||
// this list of conditions and the following disclaimer.
|
||||
//
|
||||
// * Redistribution's in binary form must reproduce the above copyright notice,
|
||||
// this list of conditions and the following disclaimer in the documentation
|
||||
// and/or other materials provided with the distribution.
|
||||
//
|
||||
// * The name of the copyright holders may not be used to endorse or promote products
|
||||
// derived from this software without specific prior written permission.
|
||||
//
|
||||
// This software is provided by the copyright holders and contributors "as is" and
|
||||
// any express or implied warranties, including, but not limited to, the implied
|
||||
// warranties of merchantability and fitness for a particular purpose are disclaimed.
|
||||
// In no event shall the Intel Corporation or contributors be liable for any direct,
|
||||
// indirect, incidental, special, exemplary, or consequential damages
|
||||
// (including, but not limited to, procurement of substitute goods or services;
|
||||
// loss of use, data, or profits; or business interruption) however caused
|
||||
// and on any theory of liability, whether in contract, strict liability,
|
||||
// or tort (including negligence or otherwise) arising in any way out of
|
||||
// the use of this software, even if advised of the possibility of such damage.
|
||||
//
|
||||
// Authors:
|
||||
// * Anatoly Baksheev, Itseez Inc. myname.mysurname <> mycompany.com
|
||||
//
|
||||
//M*/
|
||||
|
||||
#include "../precomp.hpp"
|
||||
|
||||
namespace cv { namespace viz
|
||||
{
|
||||
vtkStandardNewMacro(vtkCloudMatSource);
|
||||
|
||||
template<typename _Tp> struct VtkDepthTraits;
|
||||
|
||||
template<> struct VtkDepthTraits<float>
|
||||
{
|
||||
const static int data_type = VTK_FLOAT;
|
||||
typedef vtkFloatArray array_type;
|
||||
};
|
||||
|
||||
template<> struct VtkDepthTraits<double>
|
||||
{
|
||||
const static int data_type = VTK_DOUBLE;
|
||||
typedef vtkDoubleArray array_type;
|
||||
};
|
||||
}}
|
||||
|
||||
cv::viz::vtkCloudMatSource::vtkCloudMatSource() { SetNumberOfInputPorts(0); }
|
||||
cv::viz::vtkCloudMatSource::~vtkCloudMatSource() {}
|
||||
|
||||
int cv::viz::vtkCloudMatSource::SetCloud(InputArray _cloud)
|
||||
{
|
||||
CV_Assert(_cloud.depth() == CV_32F || _cloud.depth() == CV_64F);
|
||||
CV_Assert(_cloud.channels() == 3 || _cloud.channels() == 4);
|
||||
|
||||
Mat cloud = _cloud.getMat();
|
||||
|
||||
int total = _cloud.depth() == CV_32F ? filterNanCopy<float>(cloud) : filterNanCopy<double>(cloud);
|
||||
|
||||
vertices = vtkSmartPointer<vtkCellArray>::New();
|
||||
vertices->Allocate(vertices->EstimateSize(1, total));
|
||||
vertices->InsertNextCell(total);
|
||||
for(int i = 0; i < total; ++i)
|
||||
vertices->InsertCellPoint(i);
|
||||
|
||||
return total;
|
||||
}
|
||||
|
||||
int cv::viz::vtkCloudMatSource::SetColorCloud(InputArray _cloud, InputArray _colors)
|
||||
{
|
||||
int total = SetCloud(_cloud);
|
||||
|
||||
if (_colors.empty())
|
||||
return total;
|
||||
|
||||
CV_Assert(_colors.depth() == CV_8U && _colors.channels() <= 4 && _colors.channels() != 2);
|
||||
CV_Assert(_colors.size() == _cloud.size());
|
||||
|
||||
Mat cloud = _cloud.getMat();
|
||||
Mat colors = _colors.getMat();
|
||||
|
||||
if (cloud.depth() == CV_32F)
|
||||
filterNanColorsCopy<float>(colors, cloud, total);
|
||||
else if (cloud.depth() == CV_64F)
|
||||
filterNanColorsCopy<double>(colors, cloud, total);
|
||||
|
||||
return total;
|
||||
}
|
||||
|
||||
int cv::viz::vtkCloudMatSource::SetColorCloudNormals(InputArray _cloud, InputArray _colors, InputArray _normals)
|
||||
{
|
||||
int total = SetColorCloud(_cloud, _colors);
|
||||
|
||||
if (_normals.empty())
|
||||
return total;
|
||||
|
||||
CV_Assert(_normals.depth() == CV_32F || _normals.depth() == CV_64F);
|
||||
CV_Assert(_normals.channels() == 3 || _normals.channels() == 4);
|
||||
CV_Assert(_normals.size() == _cloud.size());
|
||||
|
||||
Mat c = _cloud.getMat();
|
||||
Mat n = _normals.getMat();
|
||||
|
||||
if (n.depth() == CV_32F && c.depth() == CV_32F)
|
||||
filterNanNormalsCopy<float, float>(n, c, total);
|
||||
else if (n.depth() == CV_32F && c.depth() == CV_64F)
|
||||
filterNanNormalsCopy<float, double>(n, c, total);
|
||||
else if (n.depth() == CV_64F && c.depth() == CV_32F)
|
||||
filterNanNormalsCopy<double, float>(n, c, total);
|
||||
else if (n.depth() == CV_64F && c.depth() == CV_64F)
|
||||
filterNanNormalsCopy<double, double>(n, c, total);
|
||||
else
|
||||
CV_Error(Error::StsError, "Unsupported normals/cloud type");
|
||||
|
||||
return total;
|
||||
}
|
||||
|
||||
int cv::viz::vtkCloudMatSource::SetColorCloudNormalsTCoords(InputArray _cloud, InputArray _colors, InputArray _normals, InputArray _tcoords)
|
||||
{
|
||||
int total = SetColorCloudNormals(_cloud, _colors, _normals);
|
||||
|
||||
if (_tcoords.empty())
|
||||
return total;
|
||||
|
||||
CV_Assert(_tcoords.depth() == CV_32F || _tcoords.depth() == CV_64F);
|
||||
CV_Assert(_tcoords.channels() == 2 && _tcoords.size() == _cloud.size());
|
||||
|
||||
Mat cl = _cloud.getMat();
|
||||
Mat tc = _tcoords.getMat();
|
||||
|
||||
if (tc.depth() == CV_32F && cl.depth() == CV_32F)
|
||||
filterNanTCoordsCopy<float, float>(tc, cl, total);
|
||||
else if (tc.depth() == CV_32F && cl.depth() == CV_64F)
|
||||
filterNanTCoordsCopy<float, double>(tc, cl, total);
|
||||
else if (tc.depth() == CV_64F && cl.depth() == CV_32F)
|
||||
filterNanTCoordsCopy<double, float>(tc, cl, total);
|
||||
else if (tc.depth() == CV_64F && cl.depth() == CV_64F)
|
||||
filterNanTCoordsCopy<double, double>(tc, cl, total);
|
||||
else
|
||||
CV_Error(Error::StsError, "Unsupported tcoords/cloud type");
|
||||
|
||||
return total;
|
||||
}
|
||||
|
||||
int cv::viz::vtkCloudMatSource::RequestData(vtkInformation *vtkNotUsed(request), vtkInformationVector **vtkNotUsed(inputVector), vtkInformationVector *outputVector)
|
||||
{
|
||||
vtkInformation *outInfo = outputVector->GetInformationObject(0);
|
||||
vtkPolyData *output = vtkPolyData::SafeDownCast(outInfo->Get(vtkDataObject::DATA_OBJECT()));
|
||||
|
||||
output->SetPoints(points);
|
||||
output->SetVerts(vertices);
|
||||
if (scalars)
|
||||
output->GetPointData()->SetScalars(scalars);
|
||||
|
||||
if (normals)
|
||||
output->GetPointData()->SetNormals(normals);
|
||||
|
||||
if (tcoords)
|
||||
output->GetPointData()->SetTCoords(tcoords);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
template<typename _Tp>
|
||||
int cv::viz::vtkCloudMatSource::filterNanCopy(const Mat& cloud)
|
||||
{
|
||||
CV_DbgAssert(DataType<_Tp>::depth == cloud.depth());
|
||||
points = vtkSmartPointer<vtkPoints>::New();
|
||||
points->SetDataType(VtkDepthTraits<_Tp>::data_type);
|
||||
points->Allocate((vtkIdType)cloud.total());
|
||||
points->SetNumberOfPoints((vtkIdType)cloud.total());
|
||||
|
||||
int s_chs = cloud.channels();
|
||||
int total = 0;
|
||||
for (int y = 0; y < cloud.rows; ++y)
|
||||
{
|
||||
const _Tp* srow = cloud.ptr<_Tp>(y);
|
||||
const _Tp* send = srow + cloud.cols * s_chs;
|
||||
|
||||
for (; srow != send; srow += s_chs)
|
||||
if (!isNan(srow))
|
||||
points->SetPoint(total++, srow);
|
||||
}
|
||||
points->SetNumberOfPoints(total);
|
||||
points->Squeeze();
|
||||
return total;
|
||||
}
|
||||
|
||||
template<typename _Msk>
|
||||
void cv::viz::vtkCloudMatSource::filterNanColorsCopy(const Mat& cloud_colors, const Mat& mask, int total)
|
||||
{
|
||||
Vec3b* array = new Vec3b[total];
|
||||
Vec3b* pos = array;
|
||||
|
||||
int s_chs = cloud_colors.channels();
|
||||
int m_chs = mask.channels();
|
||||
for (int y = 0; y < cloud_colors.rows; ++y)
|
||||
{
|
||||
const unsigned char* srow = cloud_colors.ptr<unsigned char>(y);
|
||||
const unsigned char* send = srow + cloud_colors.cols * s_chs;
|
||||
const _Msk* mrow = mask.ptr<_Msk>(y);
|
||||
|
||||
if (cloud_colors.channels() == 1)
|
||||
{
|
||||
for (; srow != send; srow += s_chs, mrow += m_chs)
|
||||
if (!isNan(mrow))
|
||||
*pos++ = Vec3b(srow[0], srow[0], srow[0]);
|
||||
}
|
||||
else
|
||||
for (; srow != send; srow += s_chs, mrow += m_chs)
|
||||
if (!isNan(mrow))
|
||||
*pos++ = Vec3b(srow[2], srow[1], srow[0]);
|
||||
|
||||
}
|
||||
|
||||
scalars = vtkSmartPointer<vtkUnsignedCharArray>::New();
|
||||
scalars->SetName("Colors");
|
||||
scalars->SetNumberOfComponents(3);
|
||||
scalars->SetNumberOfTuples(total);
|
||||
scalars->SetArray(array->val, total * 3, 0, vtkUnsignedCharArray::VTK_DATA_ARRAY_DELETE);
|
||||
}
|
||||
|
||||
template<typename _Tn, typename _Msk>
|
||||
void cv::viz::vtkCloudMatSource::filterNanNormalsCopy(const Mat& cloud_normals, const Mat& mask, int total)
|
||||
{
|
||||
normals = vtkSmartPointer< typename VtkDepthTraits<_Tn>::array_type >::New();
|
||||
normals->SetName("Normals");
|
||||
normals->SetNumberOfComponents(3);
|
||||
normals->SetNumberOfTuples(total);
|
||||
|
||||
int s_chs = cloud_normals.channels();
|
||||
int m_chs = mask.channels();
|
||||
|
||||
int pos = 0;
|
||||
for (int y = 0; y < cloud_normals.rows; ++y)
|
||||
{
|
||||
const _Tn* srow = cloud_normals.ptr<_Tn>(y);
|
||||
const _Tn* send = srow + cloud_normals.cols * s_chs;
|
||||
|
||||
const _Msk* mrow = mask.ptr<_Msk>(y);
|
||||
|
||||
for (; srow != send; srow += s_chs, mrow += m_chs)
|
||||
if (!isNan(mrow))
|
||||
normals->SetTuple(pos++, srow);
|
||||
}
|
||||
}
|
||||
|
||||
template<typename _Tn, typename _Msk>
|
||||
void cv::viz::vtkCloudMatSource::filterNanTCoordsCopy(const Mat& _tcoords, const Mat& mask, int total)
|
||||
{
|
||||
typedef Vec<_Tn, 2> Vec2;
|
||||
tcoords = vtkSmartPointer< typename VtkDepthTraits<_Tn>::array_type >::New();
|
||||
tcoords->SetName("TextureCoordinates");
|
||||
tcoords->SetNumberOfComponents(2);
|
||||
tcoords->SetNumberOfTuples(total);
|
||||
|
||||
int pos = 0;
|
||||
for (int y = 0; y < mask.rows; ++y)
|
||||
{
|
||||
const Vec2* srow = _tcoords.ptr<Vec2>(y);
|
||||
const Vec2* send = srow + _tcoords.cols;
|
||||
const _Msk* mrow = mask.ptr<_Msk>(y);
|
||||
|
||||
for (; srow != send; ++srow, mrow += mask.channels())
|
||||
if (!isNan(mrow))
|
||||
tcoords->SetTuple(pos++, srow->val);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,96 @@
|
|||
/*M///////////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
|
||||
//
|
||||
// By downloading, copying, installing or using the software you agree to this license.
|
||||
// If you do not agree to this license, do not download, install,
|
||||
// copy or use the software.
|
||||
//
|
||||
//
|
||||
// License Agreement
|
||||
// For Open Source Computer Vision Library
|
||||
//
|
||||
// Copyright (C) 2013, OpenCV Foundation, all rights reserved.
|
||||
// Third party copyrights are property of their respective owners.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without modification,
|
||||
// are permitted provided that the following conditions are met:
|
||||
//
|
||||
// * Redistribution's of source code must retain the above copyright notice,
|
||||
// this list of conditions and the following disclaimer.
|
||||
//
|
||||
// * Redistribution's in binary form must reproduce the above copyright notice,
|
||||
// this list of conditions and the following disclaimer in the documentation
|
||||
// and/or other materials provided with the distribution.
|
||||
//
|
||||
// * The name of the copyright holders may not be used to endorse or promote products
|
||||
// derived from this software without specific prior written permission.
|
||||
//
|
||||
// This software is provided by the copyright holders and contributors "as is" and
|
||||
// any express or implied warranties, including, but not limited to, the implied
|
||||
// warranties of merchantability and fitness for a particular purpose are disclaimed.
|
||||
// In no event shall the Intel Corporation or contributors be liable for any direct,
|
||||
// indirect, incidental, special, exemplary, or consequential damages
|
||||
// (including, but not limited to, procurement of substitute goods or services;
|
||||
// loss of use, data, or profits; or business interruption) however caused
|
||||
// and on any theory of liability, whether in contract, strict liability,
|
||||
// or tort (including negligence or otherwise) arising in any way out of
|
||||
// the use of this software, even if advised of the possibility of such damage.
|
||||
//
|
||||
// Authors:
|
||||
// * Anatoly Baksheev, Itseez Inc. myname.mysurname <> mycompany.com
|
||||
//
|
||||
//M*/
|
||||
|
||||
#ifndef __vtkCloudMatSource_h
|
||||
#define __vtkCloudMatSource_h
|
||||
|
||||
#include <opencv2/core.hpp>
|
||||
#include <vtkPolyDataAlgorithm.h>
|
||||
#include <vtkSmartPointer.h>
|
||||
#include <vtkPoints.h>
|
||||
#include <vtkCellArray.h>
|
||||
|
||||
namespace cv
|
||||
{
|
||||
namespace viz
|
||||
{
|
||||
class vtkCloudMatSource : public vtkPolyDataAlgorithm
|
||||
{
|
||||
public:
|
||||
static vtkCloudMatSource *New();
|
||||
vtkTypeMacro(vtkCloudMatSource,vtkPolyDataAlgorithm)
|
||||
|
||||
virtual int SetCloud(InputArray cloud);
|
||||
virtual int SetColorCloud(InputArray cloud, InputArray colors);
|
||||
virtual int SetColorCloudNormals(InputArray cloud, InputArray colors, InputArray normals);
|
||||
virtual int SetColorCloudNormalsTCoords(InputArray cloud, InputArray colors, InputArray normals, InputArray tcoords);
|
||||
|
||||
protected:
|
||||
vtkCloudMatSource();
|
||||
~vtkCloudMatSource();
|
||||
|
||||
int RequestData(vtkInformation *, vtkInformationVector **, vtkInformationVector *);
|
||||
|
||||
vtkSmartPointer<vtkPoints> points;
|
||||
vtkSmartPointer<vtkCellArray> vertices;
|
||||
vtkSmartPointer<vtkUnsignedCharArray> scalars;
|
||||
vtkSmartPointer<vtkDataArray> normals;
|
||||
vtkSmartPointer<vtkDataArray> tcoords;
|
||||
private:
|
||||
vtkCloudMatSource(const vtkCloudMatSource&); // Not implemented.
|
||||
void operator=(const vtkCloudMatSource&); // Not implemented.
|
||||
|
||||
template<typename _Tp> int filterNanCopy(const Mat& cloud);
|
||||
template<typename _Msk> void filterNanColorsCopy(const Mat& cloud_colors, const Mat& mask, int total);
|
||||
|
||||
template<typename _Tn, typename _Msk>
|
||||
void filterNanNormalsCopy(const Mat& cloud_normals, const Mat& mask, int total);
|
||||
|
||||
template<typename _Tn, typename _Msk>
|
||||
void filterNanTCoordsCopy(const Mat& tcoords, const Mat& mask, int total);
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
|
@ -0,0 +1,227 @@
|
|||
/*M///////////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
|
||||
//
|
||||
// By downloading, copying, installing or using the software you agree to this license.
|
||||
// If you do not agree to this license, do not download, install,
|
||||
// copy or use the software.
|
||||
//
|
||||
//
|
||||
// License Agreement
|
||||
// For Open Source Computer Vision Library
|
||||
//
|
||||
// Copyright (C) 2013, OpenCV Foundation, all rights reserved.
|
||||
// Third party copyrights are property of their respective owners.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without modification,
|
||||
// are permitted provided that the following conditions are met:
|
||||
//
|
||||
// * Redistribution's of source code must retain the above copyright notice,
|
||||
// this list of conditions and the following disclaimer.
|
||||
//
|
||||
// * Redistribution's in binary form must reproduce the above copyright notice,
|
||||
// this list of conditions and the following disclaimer in the documentation
|
||||
// and/or other materials provided with the distribution.
|
||||
//
|
||||
// * The name of the copyright holders may not be used to endorse or promote products
|
||||
// derived from this software without specific prior written permission.
|
||||
//
|
||||
// This software is provided by the copyright holders and contributors "as is" and
|
||||
// any express or implied warranties, including, but not limited to, the implied
|
||||
// warranties of merchantability and fitness for a particular purpose are disclaimed.
|
||||
// In no event shall the Intel Corporation or contributors be liable for any direct,
|
||||
// indirect, incidental, special, exemplary, or consequential damages
|
||||
// (including, but not limited to, procurement of substitute goods or services;
|
||||
// loss of use, data, or profits; or business interruption) however caused
|
||||
// and on any theory of liability, whether in contract, strict liability,
|
||||
// or tort (including negligence or otherwise) arising in any way out of
|
||||
// the use of this software, even if advised of the possibility of such damage.
|
||||
//
|
||||
// Authors:
|
||||
// * Anatoly Baksheev, Itseez Inc. myname.mysurname <> mycompany.com
|
||||
//
|
||||
// This workaround code was taken from PCL library(www.pointclouds.org)
|
||||
//
|
||||
//M*/
|
||||
|
||||
#import <Cocoa/Cocoa.h>
|
||||
#include <vtkCocoaRenderWindow.h>
|
||||
#include <vtkCocoaRenderWindowInteractor.h>
|
||||
#include <vtkObjectFactory.h>
|
||||
#include <vtkSmartPointer.h>
|
||||
#include <vtkVersion.h>
|
||||
|
||||
namespace cv { namespace viz {
|
||||
vtkSmartPointer<vtkRenderWindowInteractor> vtkCocoaRenderWindowInteractorNew();
|
||||
}} // namespace
|
||||
|
||||
#if ((VTK_MAJOR_VERSION < 6) || ((VTK_MAJOR_VERSION == 6) && (VTK_MINOR_VERSION < 2)))
|
||||
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
@interface vtkCocoaServerFix : NSObject
|
||||
{
|
||||
vtkCocoaRenderWindow* renWin;
|
||||
}
|
||||
|
||||
+ (id)cocoaServerWithRenderWindow:(vtkCocoaRenderWindow*)inRenderWindow;
|
||||
|
||||
- (void)start;
|
||||
- (void)stop;
|
||||
- (void)breakEventLoop;
|
||||
|
||||
@end
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
@implementation vtkCocoaServerFix
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
- (id)initWithRenderWindow:(vtkCocoaRenderWindow *)inRenderWindow
|
||||
{
|
||||
self = [super init];
|
||||
if (self)
|
||||
renWin = inRenderWindow;
|
||||
return self;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
+ (id)cocoaServerWithRenderWindow:(vtkCocoaRenderWindow *)inRenderWindow
|
||||
{
|
||||
vtkCocoaServerFix *server = [[[vtkCocoaServerFix alloc] initWithRenderWindow:inRenderWindow] autorelease];
|
||||
return server;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
- (void)start
|
||||
{
|
||||
// Retrieve the NSWindow.
|
||||
NSWindow *win = nil;
|
||||
if (renWin)
|
||||
{
|
||||
win = reinterpret_cast<NSWindow*> (renWin->GetRootWindow ());
|
||||
|
||||
// We don't want to be informed of every window closing, so check for nil.
|
||||
if (win != nil)
|
||||
{
|
||||
// Register for the windowWillClose notification in order to stop the run loop if the window closes.
|
||||
NSNotificationCenter *nc = [NSNotificationCenter defaultCenter];
|
||||
[nc addObserver:self selector:@selector(windowWillClose:) name:NSWindowWillCloseNotification object:win];
|
||||
}
|
||||
}
|
||||
// Start the NSApplication's run loop
|
||||
NSApplication* application = [NSApplication sharedApplication];
|
||||
[application run];
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
- (void)stop
|
||||
{
|
||||
[self breakEventLoop];
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
- (void)breakEventLoop
|
||||
{
|
||||
NSApplication* application = [NSApplication sharedApplication];
|
||||
[application stop:application];
|
||||
|
||||
NSEvent *event = [NSEvent otherEventWithType:NSApplicationDefined
|
||||
location:NSMakePoint(0.0,0.0)
|
||||
modifierFlags:0
|
||||
timestamp:0
|
||||
windowNumber:-1
|
||||
context:nil
|
||||
subtype:0
|
||||
data1:0
|
||||
data2:0];
|
||||
[application postEvent:event atStart:YES];
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
- (void)windowWillClose:(NSNotification*)aNotification
|
||||
{
|
||||
(void)aNotification;
|
||||
|
||||
NSNotificationCenter *nc = [NSNotificationCenter defaultCenter];
|
||||
[nc removeObserver:self name:NSWindowWillCloseNotification object:nil];
|
||||
|
||||
if (renWin)
|
||||
{
|
||||
int windowCreated = renWin->GetWindowCreated ();
|
||||
if (windowCreated)
|
||||
{
|
||||
[self breakEventLoop];
|
||||
|
||||
// The NSWindow is closing, so prevent anyone from accidentally using it
|
||||
renWin->SetRootWindow(NULL);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
namespace cv { namespace viz
|
||||
{
|
||||
class vtkCocoaRenderWindowInteractorFix : public vtkCocoaRenderWindowInteractor
|
||||
{
|
||||
public:
|
||||
static vtkCocoaRenderWindowInteractorFix *New ();
|
||||
vtkTypeMacro (vtkCocoaRenderWindowInteractorFix, vtkCocoaRenderWindowInteractor)
|
||||
|
||||
virtual void Start ();
|
||||
virtual void TerminateApp ();
|
||||
|
||||
protected:
|
||||
vtkCocoaRenderWindowInteractorFix () {}
|
||||
~vtkCocoaRenderWindowInteractorFix () {}
|
||||
|
||||
private:
|
||||
vtkCocoaRenderWindowInteractorFix (const vtkCocoaRenderWindowInteractorFix&); // Not implemented.
|
||||
void operator = (const vtkCocoaRenderWindowInteractorFix&); // Not implemented.
|
||||
};
|
||||
|
||||
vtkStandardNewMacro (vtkCocoaRenderWindowInteractorFix)
|
||||
}}
|
||||
|
||||
void cv::viz::vtkCocoaRenderWindowInteractorFix::Start ()
|
||||
{
|
||||
vtkCocoaRenderWindow* renWin = vtkCocoaRenderWindow::SafeDownCast(this->GetRenderWindow ());
|
||||
if (renWin != NULL)
|
||||
{
|
||||
vtkCocoaServerFix *server = reinterpret_cast<vtkCocoaServerFix*> (this->GetCocoaServer ());
|
||||
if (!this->GetCocoaServer ())
|
||||
{
|
||||
server = [vtkCocoaServerFix cocoaServerWithRenderWindow:renWin];
|
||||
this->SetCocoaServer (reinterpret_cast<void*> (server));
|
||||
}
|
||||
|
||||
[server start];
|
||||
}
|
||||
}
|
||||
|
||||
void cv::viz::vtkCocoaRenderWindowInteractorFix::TerminateApp ()
|
||||
{
|
||||
vtkCocoaRenderWindow *renWin = vtkCocoaRenderWindow::SafeDownCast (this->RenderWindow);
|
||||
if (renWin)
|
||||
{
|
||||
vtkCocoaServerFix *server = reinterpret_cast<vtkCocoaServerFix*> (this->GetCocoaServer ());
|
||||
[server stop];
|
||||
}
|
||||
}
|
||||
|
||||
vtkSmartPointer<vtkRenderWindowInteractor> cv::viz::vtkCocoaRenderWindowInteractorNew()
|
||||
{
|
||||
return vtkSmartPointer<vtkCocoaRenderWindowInteractorFix>::New();
|
||||
}
|
||||
|
||||
|
||||
#else
|
||||
|
||||
vtkSmartPointer<vtkRenderWindowInteractor> cv::viz::vtkCocoaRenderWindowInteractorNew()
|
||||
{
|
||||
return vtkSmartPointer<vtkCocoaRenderWindowInteractor>::New();
|
||||
}
|
||||
|
||||
#endif
|
|
@ -0,0 +1,143 @@
|
|||
/*M///////////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
|
||||
//
|
||||
// By downloading, copying, installing or using the software you agree to this license.
|
||||
// If you do not agree to this license, do not download, install,
|
||||
// copy or use the software.
|
||||
//
|
||||
//
|
||||
// License Agreement
|
||||
// For Open Source Computer Vision Library
|
||||
//
|
||||
// Copyright (C) 2013, OpenCV Foundation, all rights reserved.
|
||||
// Third party copyrights are property of their respective owners.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without modification,
|
||||
// are permitted provided that the following conditions are met:
|
||||
//
|
||||
// * Redistribution's of source code must retain the above copyright notice,
|
||||
// this list of conditions and the following disclaimer.
|
||||
//
|
||||
// * Redistribution's in binary form must reproduce the above copyright notice,
|
||||
// this list of conditions and the following disclaimer in the documentation
|
||||
// and/or other materials provided with the distribution.
|
||||
//
|
||||
// * The name of the copyright holders may not be used to endorse or promote products
|
||||
// derived from this software without specific prior written permission.
|
||||
//
|
||||
// This software is provided by the copyright holders and contributors "as is" and
|
||||
// any express or implied warranties, including, but not limited to, the implied
|
||||
// warranties of merchantability and fitness for a particular purpose are disclaimed.
|
||||
// In no event shall the Intel Corporation or contributors be liable for any direct,
|
||||
// indirect, incidental, special, exemplary, or consequential damages
|
||||
// (including, but not limited to, procurement of substitute goods or services;
|
||||
// loss of use, data, or profits; or business interruption) however caused
|
||||
// and on any theory of liability, whether in contract, strict liability,
|
||||
// or tort (including negligence or otherwise) arising in any way out of
|
||||
// the use of this software, even if advised of the possibility of such damage.
|
||||
//
|
||||
// Authors:
|
||||
// * Anatoly Baksheev, Itseez Inc. myname.mysurname <> mycompany.com
|
||||
//
|
||||
//M*/
|
||||
|
||||
#include "../precomp.hpp"
|
||||
|
||||
namespace cv { namespace viz
|
||||
{
|
||||
vtkStandardNewMacro(vtkImageMatSource);
|
||||
}}
|
||||
|
||||
cv::viz::vtkImageMatSource::vtkImageMatSource()
|
||||
{
|
||||
this->SetNumberOfInputPorts(0);
|
||||
this->ImageData = vtkSmartPointer<vtkImageData>::New();
|
||||
}
|
||||
|
||||
int cv::viz::vtkImageMatSource::RequestInformation(vtkInformation *, vtkInformationVector**, vtkInformationVector *outputVector)
|
||||
{
|
||||
vtkInformation* outInfo = outputVector->GetInformationObject(0);
|
||||
|
||||
outInfo->Set(vtkStreamingDemandDrivenPipeline::WHOLE_EXTENT(), this->ImageData->GetExtent(), 6);
|
||||
outInfo->Set(vtkDataObject::SPACING(), 1.0, 1.0, 1.0);
|
||||
outInfo->Set(vtkDataObject::ORIGIN(), 0.0, 0.0, 0.0);
|
||||
|
||||
vtkDataObject::SetPointDataActiveScalarInfo(outInfo, this->ImageData->GetScalarType(), this->ImageData->GetNumberOfScalarComponents());
|
||||
return 1;
|
||||
}
|
||||
|
||||
int cv::viz::vtkImageMatSource::RequestData(vtkInformation*, vtkInformationVector**, vtkInformationVector *outputVector)
|
||||
{
|
||||
vtkInformation *outInfo = outputVector->GetInformationObject(0);
|
||||
|
||||
vtkImageData *output = vtkImageData::SafeDownCast(outInfo->Get(vtkDataObject::DATA_OBJECT()) );
|
||||
output->ShallowCopy(this->ImageData);
|
||||
return 1;
|
||||
}
|
||||
|
||||
void cv::viz::vtkImageMatSource::SetImage(InputArray _image)
|
||||
{
|
||||
CV_Assert(_image.depth() == CV_8U && (_image.channels() == 1 || _image.channels() == 3 || _image.channels() == 4));
|
||||
|
||||
Mat image = _image.getMat();
|
||||
|
||||
this->ImageData->SetDimensions(image.cols, image.rows, 1);
|
||||
#if VTK_MAJOR_VERSION <= 5
|
||||
this->ImageData->SetNumberOfScalarComponents(image.channels());
|
||||
this->ImageData->SetScalarTypeToUnsignedChar();
|
||||
this->ImageData->AllocateScalars();
|
||||
#else
|
||||
this->ImageData->AllocateScalars(VTK_UNSIGNED_CHAR, image.channels());
|
||||
#endif
|
||||
|
||||
switch(image.channels())
|
||||
{
|
||||
case 1: copyGrayImage(image, this->ImageData); break;
|
||||
case 3: copyRGBImage (image, this->ImageData); break;
|
||||
case 4: copyRGBAImage(image, this->ImageData); break;
|
||||
}
|
||||
this->ImageData->Modified();
|
||||
}
|
||||
|
||||
void cv::viz::vtkImageMatSource::copyGrayImage(const Mat &source, vtkSmartPointer<vtkImageData> output)
|
||||
{
|
||||
unsigned char* dptr = reinterpret_cast<unsigned char*>(output->GetScalarPointer());
|
||||
size_t elem_step = output->GetIncrements()[1]/sizeof(unsigned char);
|
||||
|
||||
for (int y = 0; y < source.rows; ++y)
|
||||
{
|
||||
unsigned char* drow = dptr + elem_step * y;
|
||||
const unsigned char *srow = source.ptr<unsigned char>(y);
|
||||
for (int x = 0; x < source.cols; ++x)
|
||||
drow[x] = *srow++;
|
||||
}
|
||||
}
|
||||
|
||||
void cv::viz::vtkImageMatSource::copyRGBImage(const Mat &source, vtkSmartPointer<vtkImageData> output)
|
||||
{
|
||||
Vec3b* dptr = reinterpret_cast<Vec3b*>(output->GetScalarPointer());
|
||||
size_t elem_step = output->GetIncrements()[1]/sizeof(Vec3b);
|
||||
|
||||
for (int y = 0; y < source.rows; ++y)
|
||||
{
|
||||
Vec3b* drow = dptr + elem_step * y;
|
||||
const unsigned char *srow = source.ptr<unsigned char>(y);
|
||||
for (int x = 0; x < source.cols; ++x, srow += source.channels())
|
||||
drow[x] = Vec3b(srow[2], srow[1], srow[0]);
|
||||
}
|
||||
}
|
||||
|
||||
void cv::viz::vtkImageMatSource::copyRGBAImage(const Mat &source, vtkSmartPointer<vtkImageData> output)
|
||||
{
|
||||
Vec4b* dptr = reinterpret_cast<Vec4b*>(output->GetScalarPointer());
|
||||
size_t elem_step = output->GetIncrements()[1]/sizeof(Vec4b);
|
||||
|
||||
for (int y = 0; y < source.rows; ++y)
|
||||
{
|
||||
Vec4b* drow = dptr + elem_step * y;
|
||||
const unsigned char *srow = source.ptr<unsigned char>(y);
|
||||
for (int x = 0; x < source.cols; ++x, srow += source.channels())
|
||||
drow[x] = Vec4b(srow[2], srow[1], srow[0], srow[3]);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,82 @@
|
|||
/*M///////////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
|
||||
//
|
||||
// By downloading, copying, installing or using the software you agree to this license.
|
||||
// If you do not agree to this license, do not download, install,
|
||||
// copy or use the software.
|
||||
//
|
||||
//
|
||||
// License Agreement
|
||||
// For Open Source Computer Vision Library
|
||||
//
|
||||
// Copyright (C) 2013, OpenCV Foundation, all rights reserved.
|
||||
// Third party copyrights are property of their respective owners.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without modification,
|
||||
// are permitted provided that the following conditions are met:
|
||||
//
|
||||
// * Redistribution's of source code must retain the above copyright notice,
|
||||
// this list of conditions and the following disclaimer.
|
||||
//
|
||||
// * Redistribution's in binary form must reproduce the above copyright notice,
|
||||
// this list of conditions and the following disclaimer in the documentation
|
||||
// and/or other materials provided with the distribution.
|
||||
//
|
||||
// * The name of the copyright holders may not be used to endorse or promote products
|
||||
// derived from this software without specific prior written permission.
|
||||
//
|
||||
// This software is provided by the copyright holders and contributors "as is" and
|
||||
// any express or implied warranties, including, but not limited to, the implied
|
||||
// warranties of merchantability and fitness for a particular purpose are disclaimed.
|
||||
// In no event shall the Intel Corporation or contributors be liable for any direct,
|
||||
// indirect, incidental, special, exemplary, or consequential damages
|
||||
// (including, but not limited to, procurement of substitute goods or services;
|
||||
// loss of use, data, or profits; or business interruption) however caused
|
||||
// and on any theory of liability, whether in contract, strict liability,
|
||||
// or tort (including negligence or otherwise) arising in any way out of
|
||||
// the use of this software, even if advised of the possibility of such damage.
|
||||
//
|
||||
// Authors:
|
||||
// * Anatoly Baksheev, Itseez Inc. myname.mysurname <> mycompany.com
|
||||
//
|
||||
//M*/
|
||||
|
||||
#include "../precomp.hpp"
|
||||
|
||||
#ifndef __vtkImageMatSource_h
|
||||
#define __vtkImageMatSource_h
|
||||
|
||||
namespace cv
|
||||
{
|
||||
namespace viz
|
||||
{
|
||||
class vtkImageMatSource : public vtkImageAlgorithm
|
||||
{
|
||||
public:
|
||||
static vtkImageMatSource *New();
|
||||
vtkTypeMacro(vtkImageMatSource,vtkImageAlgorithm);
|
||||
|
||||
void SetImage(InputArray image);
|
||||
|
||||
protected:
|
||||
vtkImageMatSource();
|
||||
~vtkImageMatSource() {}
|
||||
|
||||
vtkSmartPointer<vtkImageData> ImageData;
|
||||
|
||||
int RequestInformation(vtkInformation*, vtkInformationVector**, vtkInformationVector*);
|
||||
int RequestData (vtkInformation*, vtkInformationVector**, vtkInformationVector*);
|
||||
private:
|
||||
vtkImageMatSource(const vtkImageMatSource&); // Not implemented.
|
||||
void operator=(const vtkImageMatSource&); // Not implemented.
|
||||
|
||||
static void copyGrayImage(const Mat &source, vtkSmartPointer<vtkImageData> output);
|
||||
static void copyRGBImage (const Mat &source, vtkSmartPointer<vtkImageData> output);
|
||||
static void copyRGBAImage(const Mat &source, vtkSmartPointer<vtkImageData> output);
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#endif
|
|
@ -0,0 +1,274 @@
|
|||
/*M///////////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
|
||||
//
|
||||
// By downloading, copying, installing or using the software you agree to this license.
|
||||
// If you do not agree to this license, do not download, install,
|
||||
// copy or use the software.
|
||||
//
|
||||
//
|
||||
// License Agreement
|
||||
// For Open Source Computer Vision Library
|
||||
//
|
||||
// Copyright (C) 2013, OpenCV Foundation, all rights reserved.
|
||||
// Third party copyrights are property of their respective owners.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without modification,
|
||||
// are permitted provided that the following conditions are met:
|
||||
//
|
||||
// * Redistribution's of source code must retain the above copyright notice,
|
||||
// this list of conditions and the following disclaimer.
|
||||
//
|
||||
// * Redistribution's in binary form must reproduce the above copyright notice,
|
||||
// this list of conditions and the following disclaimer in the documentation
|
||||
// and/or other materials provided with the distribution.
|
||||
//
|
||||
// * The name of the copyright holders may not be used to endorse or promote products
|
||||
// derived from this software without specific prior written permission.
|
||||
//
|
||||
// This software is provided by the copyright holders and contributors "as is" and
|
||||
// any express or implied warranties, including, but not limited to, the implied
|
||||
// warranties of merchantability and fitness for a particular purpose are disclaimed.
|
||||
// In no event shall the Intel Corporation or contributors be liable for any direct,
|
||||
// indirect, incidental, special, exemplary, or consequential damages
|
||||
// (including, but not limited to, procurement of substitute goods or services;
|
||||
// loss of use, data, or profits; or business interruption) however caused
|
||||
// and on any theory of liability, whether in contract, strict liability,
|
||||
// or tort (including negligence or otherwise) arising in any way out of
|
||||
// the use of this software, even if advised of the possibility of such damage.
|
||||
//
|
||||
// Authors:
|
||||
// * Anatoly Baksheev, Itseez Inc. myname.mysurname <> mycompany.com
|
||||
//
|
||||
//M*/
|
||||
|
||||
#include "../precomp.hpp"
|
||||
|
||||
namespace cv { namespace viz
|
||||
{
|
||||
vtkStandardNewMacro(vtkOBJWriter);
|
||||
}}
|
||||
|
||||
cv::viz::vtkOBJWriter::vtkOBJWriter()
|
||||
{
|
||||
std::ofstream fout; // only used to extract the default precision
|
||||
this->DecimalPrecision = fout.precision();
|
||||
this->FileName = NULL;
|
||||
}
|
||||
|
||||
cv::viz::vtkOBJWriter::~vtkOBJWriter(){}
|
||||
|
||||
void cv::viz::vtkOBJWriter::WriteData()
|
||||
{
|
||||
vtkPolyData *input = this->GetInput();
|
||||
if (!input)
|
||||
return;
|
||||
|
||||
if (!this->FileName )
|
||||
{
|
||||
vtkErrorMacro(<< "No FileName specified! Can't write!");
|
||||
this->SetErrorCode(vtkErrorCode::NoFileNameError);
|
||||
return;
|
||||
}
|
||||
|
||||
vtkDebugMacro(<<"Opening vtk file for writing...");
|
||||
std::ostream *outfilep = new std::ofstream(this->FileName, ios::out);
|
||||
if (outfilep->fail())
|
||||
{
|
||||
vtkErrorMacro(<< "Unable to open file: "<< this->FileName);
|
||||
this->SetErrorCode(vtkErrorCode::CannotOpenFileError);
|
||||
delete outfilep;
|
||||
return;
|
||||
}
|
||||
|
||||
std::ostream& outfile = *outfilep;
|
||||
|
||||
//write header
|
||||
outfile << "# wavefront obj file written by opencv viz module" << std::endl << std::endl;
|
||||
outfile << "mtllib NONE" << std::endl << std::endl;
|
||||
|
||||
// write out the points
|
||||
for (int i = 0; i < input->GetNumberOfPoints(); i++)
|
||||
{
|
||||
Vec3d p;
|
||||
input->GetPoint(i, p.val);
|
||||
outfile << std::setprecision(this->DecimalPrecision) << "v " << p[0] << " " << p[1] << " " << p[2] << std::endl;
|
||||
}
|
||||
|
||||
const int idStart = 1;
|
||||
|
||||
// write out the point data
|
||||
vtkSmartPointer<vtkDataArray> normals = input->GetPointData()->GetNormals();
|
||||
if(normals)
|
||||
{
|
||||
for (int i = 0; i < normals->GetNumberOfTuples(); i++)
|
||||
{
|
||||
Vec3d p;
|
||||
normals->GetTuple(i, p.val);
|
||||
outfile << std::setprecision(this->DecimalPrecision) << "vn " << p[0] << " " << p[1] << " " << p[2] << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
vtkSmartPointer<vtkDataArray> tcoords = input->GetPointData()->GetTCoords();
|
||||
if (tcoords)
|
||||
{
|
||||
for (int i = 0; i < tcoords->GetNumberOfTuples(); i++)
|
||||
{
|
||||
Vec2d p;
|
||||
tcoords->GetTuple(i, p.val);
|
||||
outfile << std::setprecision(this->DecimalPrecision) << "vt " << p[0] << " " << p[1] << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
// write out a group name and material
|
||||
outfile << std::endl << "g grp" << idStart << std::endl;
|
||||
outfile << "usemtl mtlNONE" << std::endl;
|
||||
|
||||
// write out verts if any
|
||||
if (input->GetNumberOfVerts() > 0)
|
||||
{
|
||||
vtkIdType npts = 0;
|
||||
CellIterT index = 0;
|
||||
vtkCellArray *cells = input->GetVerts();
|
||||
for (cells->InitTraversal(); cells->GetNextCell(npts, index); )
|
||||
{
|
||||
outfile << "p ";
|
||||
for (int i = 0; i < npts; i++)
|
||||
outfile << index[i] + idStart << " ";
|
||||
outfile << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
// write out lines if any
|
||||
if (input->GetNumberOfLines() > 0)
|
||||
{
|
||||
vtkIdType npts = 0;
|
||||
CellIterT index = 0;
|
||||
vtkCellArray *cells = input->GetLines();
|
||||
for (cells->InitTraversal(); cells->GetNextCell(npts, index); )
|
||||
{
|
||||
outfile << "l ";
|
||||
if (tcoords)
|
||||
{
|
||||
for (int i = 0; i < npts; i++)
|
||||
outfile << index[i] + idStart << "/" << index[i] + idStart << " ";
|
||||
}
|
||||
else
|
||||
for (int i = 0; i < npts; i++)
|
||||
outfile << index[i] + idStart << " ";
|
||||
|
||||
outfile << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
// write out polys if any
|
||||
if (input->GetNumberOfPolys() > 0)
|
||||
{
|
||||
vtkIdType npts = 0;
|
||||
CellIterT index = 0;
|
||||
vtkCellArray *cells = input->GetPolys();
|
||||
for (cells->InitTraversal(); cells->GetNextCell(npts, index); )
|
||||
{
|
||||
outfile << "f ";
|
||||
for (int i = 0; i < npts; i++)
|
||||
{
|
||||
if (normals)
|
||||
{
|
||||
if (tcoords)
|
||||
outfile << index[i] + idStart << "/" << index[i] + idStart << "/" << index[i] + idStart << " ";
|
||||
else
|
||||
outfile << index[i] + idStart << "//" << index[i] + idStart << " ";
|
||||
}
|
||||
else
|
||||
{
|
||||
if (tcoords)
|
||||
outfile << index[i] + idStart << " " << index[i] + idStart << " ";
|
||||
else
|
||||
outfile << index[i] + idStart << " ";
|
||||
}
|
||||
}
|
||||
outfile << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
// write out tstrips if any
|
||||
if (input->GetNumberOfStrips() > 0)
|
||||
{
|
||||
vtkIdType npts = 0;
|
||||
CellIterT index = 0;
|
||||
vtkCellArray *cells = input->GetStrips();
|
||||
for (cells->InitTraversal(); cells->GetNextCell(npts, index); )
|
||||
{
|
||||
for (int i = 2, i1, i2; i < npts; ++i)
|
||||
{
|
||||
if (i % 2)
|
||||
{
|
||||
i1 = i - 1;
|
||||
i2 = i - 2;
|
||||
}
|
||||
else
|
||||
{
|
||||
i1 = i - 1;
|
||||
i2 = i - 2;
|
||||
}
|
||||
|
||||
if(normals)
|
||||
{
|
||||
if (tcoords)
|
||||
{
|
||||
outfile << "f " << index[i1] + idStart << "/" << index[i1] + idStart << "/" << index[i1] + idStart << " "
|
||||
<< index[i2]+ idStart << "/" << index[i2] + idStart << "/" << index[i2] + idStart << " "
|
||||
<< index[i] + idStart << "/" << index[i] + idStart << "/" << index[i] + idStart << std::endl;
|
||||
}
|
||||
else
|
||||
{
|
||||
outfile << "f " << index[i1] + idStart << "//" << index[i1] + idStart << " " << index[i2] + idStart
|
||||
<< "//" << index[i2] + idStart << " " << index[i] + idStart << "//" << index[i] + idStart << std::endl;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (tcoords)
|
||||
{
|
||||
outfile << "f " << index[i1] + idStart << "/" << index[i1] + idStart << " " << index[i2] + idStart
|
||||
<< "/" << index[i2] + idStart << " " << index[i] + idStart << "/" << index[i] + idStart << std::endl;
|
||||
}
|
||||
else
|
||||
outfile << "f " << index[i1] + idStart << " " << index[i2] + idStart << " " << index[i] + idStart << std::endl;
|
||||
}
|
||||
} /* for (int i = 2; i < npts; ++i) */
|
||||
}
|
||||
} /* if (input->GetNumberOfStrips() > 0) */
|
||||
|
||||
vtkDebugMacro(<<"Closing vtk file\n");
|
||||
delete outfilep;
|
||||
|
||||
// Delete the file if an error occurred
|
||||
if (this->ErrorCode == vtkErrorCode::OutOfDiskSpaceError)
|
||||
{
|
||||
vtkErrorMacro("Ran out of disk space; deleting file: " << this->FileName);
|
||||
unlink(this->FileName);
|
||||
}
|
||||
}
|
||||
|
||||
void cv::viz::vtkOBJWriter::PrintSelf(ostream& os, vtkIndent indent)
|
||||
{
|
||||
Superclass::PrintSelf(os, indent);
|
||||
os << indent << "DecimalPrecision: " << DecimalPrecision << "\n";
|
||||
}
|
||||
|
||||
int cv::viz::vtkOBJWriter::FillInputPortInformation(int, vtkInformation *info)
|
||||
{
|
||||
info->Set(vtkAlgorithm::INPUT_REQUIRED_DATA_TYPE(), "vtkPolyData");
|
||||
return 1;
|
||||
}
|
||||
|
||||
vtkPolyData* cv::viz::vtkOBJWriter::GetInput()
|
||||
{
|
||||
return vtkPolyData::SafeDownCast(this->Superclass::GetInput());
|
||||
}
|
||||
|
||||
vtkPolyData* cv::viz::vtkOBJWriter::GetInput(int port)
|
||||
{
|
||||
return vtkPolyData::SafeDownCast(this->Superclass::GetInput(port));
|
||||
}
|
|
@ -0,0 +1,91 @@
|
|||
/*M///////////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
|
||||
//
|
||||
// By downloading, copying, installing or using the software you agree to this license.
|
||||
// If you do not agree to this license, do not download, install,
|
||||
// copy or use the software.
|
||||
//
|
||||
//
|
||||
// License Agreement
|
||||
// For Open Source Computer Vision Library
|
||||
//
|
||||
// Copyright (C) 2013, OpenCV Foundation, all rights reserved.
|
||||
// Third party copyrights are property of their respective owners.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without modification,
|
||||
// are permitted provided that the following conditions are met:
|
||||
//
|
||||
// * Redistribution's of source code must retain the above copyright notice,
|
||||
// this list of conditions and the following disclaimer.
|
||||
//
|
||||
// * Redistribution's in binary form must reproduce the above copyright notice,
|
||||
// this list of conditions and the following disclaimer in the documentation
|
||||
// and/or other materials provided with the distribution.
|
||||
//
|
||||
// * The name of the copyright holders may not be used to endorse or promote products
|
||||
// derived from this software without specific prior written permission.
|
||||
//
|
||||
// This software is provided by the copyright holders and contributors "as is" and
|
||||
// any express or implied warranties, including, but not limited to, the implied
|
||||
// warranties of merchantability and fitness for a particular purpose are disclaimed.
|
||||
// In no event shall the Intel Corporation or contributors be liable for any direct,
|
||||
// indirect, incidental, special, exemplary, or consequential damages
|
||||
// (including, but not limited to, procurement of substitute goods or services;
|
||||
// loss of use, data, or profits; or business interruption) however caused
|
||||
// and on any theory of liability, whether in contract, strict liability,
|
||||
// or tort (including negligence or otherwise) arising in any way out of
|
||||
// the use of this software, even if advised of the possibility of such damage.
|
||||
//
|
||||
// Authors:
|
||||
// * Anatoly Baksheev, Itseez Inc. myname.mysurname <> mycompany.com
|
||||
//
|
||||
//M*/
|
||||
|
||||
#ifndef __vtkOBJWriter_h
|
||||
#define __vtkOBJWriter_h
|
||||
|
||||
#include <vtkWriter.h>
|
||||
|
||||
namespace cv
|
||||
{
|
||||
namespace viz
|
||||
{
|
||||
class vtkOBJWriter : public vtkWriter
|
||||
{
|
||||
public:
|
||||
static vtkOBJWriter *New();
|
||||
vtkTypeMacro(vtkOBJWriter,vtkWriter)
|
||||
void PrintSelf(ostream& os, vtkIndent indent);
|
||||
|
||||
vtkGetMacro(DecimalPrecision, int)
|
||||
vtkSetMacro(DecimalPrecision, int)
|
||||
|
||||
// Description:
|
||||
// Specify file name of data file to write.
|
||||
vtkSetStringMacro(FileName)
|
||||
vtkGetStringMacro(FileName)
|
||||
|
||||
// Description:
|
||||
// Get the input to this writer.
|
||||
vtkPolyData* GetInput();
|
||||
vtkPolyData* GetInput(int port);
|
||||
|
||||
protected:
|
||||
vtkOBJWriter();
|
||||
~vtkOBJWriter();
|
||||
|
||||
void WriteData();
|
||||
int FillInputPortInformation(int port, vtkInformation *info);
|
||||
|
||||
int DecimalPrecision;
|
||||
char *FileName;
|
||||
|
||||
private:
|
||||
vtkOBJWriter(const vtkOBJWriter&); // Not implemented.
|
||||
void operator=(const vtkOBJWriter&); // Not implemented.
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
|
@ -0,0 +1,110 @@
|
|||
/*M///////////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
|
||||
//
|
||||
// By downloading, copying, installing or using the software you agree to this license.
|
||||
// If you do not agree to this license, do not download, install,
|
||||
// copy or use the software.
|
||||
//
|
||||
//
|
||||
// License Agreement
|
||||
// For Open Source Computer Vision Library
|
||||
//
|
||||
// Copyright (C) 2013, OpenCV Foundation, all rights reserved.
|
||||
// Third party copyrights are property of their respective owners.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without modification,
|
||||
// are permitted provided that the following conditions are met:
|
||||
//
|
||||
// * Redistribution's of source code must retain the above copyright notice,
|
||||
// this list of conditions and the following disclaimer.
|
||||
//
|
||||
// * Redistribution's in binary form must reproduce the above copyright notice,
|
||||
// this list of conditions and the following disclaimer in the documentation
|
||||
// and/or other materials provided with the distribution.
|
||||
//
|
||||
// * The name of the copyright holders may not be used to endorse or promote products
|
||||
// derived from this software without specific prior written permission.
|
||||
//
|
||||
// This software is provided by the copyright holders and contributors "as is" and
|
||||
// any express or implied warranties, including, but not limited to, the implied
|
||||
// warranties of merchantability and fitness for a particular purpose are disclaimed.
|
||||
// In no event shall the Intel Corporation or contributors be liable for any direct,
|
||||
// indirect, incidental, special, exemplary, or consequential damages
|
||||
// (including, but not limited to, procurement of substitute goods or services;
|
||||
// loss of use, data, or profits; or business interruption) however caused
|
||||
// and on any theory of liability, whether in contract, strict liability,
|
||||
// or tort (including negligence or otherwise) arising in any way out of
|
||||
// the use of this software, even if advised of the possibility of such damage.
|
||||
//
|
||||
// Authors:
|
||||
// * Anatoly Baksheev, Itseez Inc. myname.mysurname <> mycompany.com
|
||||
//
|
||||
//M*/
|
||||
|
||||
#include "../precomp.hpp"
|
||||
|
||||
namespace cv { namespace viz
|
||||
{
|
||||
vtkStandardNewMacro(vtkTrajectorySource);
|
||||
}}
|
||||
|
||||
cv::viz::vtkTrajectorySource::vtkTrajectorySource() { SetNumberOfInputPorts(0); }
|
||||
cv::viz::vtkTrajectorySource::~vtkTrajectorySource() {}
|
||||
|
||||
void cv::viz::vtkTrajectorySource::SetTrajectory(InputArray _traj)
|
||||
{
|
||||
CV_Assert(_traj.kind() == _InputArray::STD_VECTOR || _traj.kind() == _InputArray::MAT);
|
||||
CV_Assert(_traj.type() == CV_32FC(16) || _traj.type() == CV_64FC(16));
|
||||
|
||||
Mat traj;
|
||||
_traj.getMat().convertTo(traj, CV_64F);
|
||||
const Affine3d* dpath = traj.ptr<Affine3d>();
|
||||
size_t total = traj.total();
|
||||
|
||||
points = vtkSmartPointer<vtkPoints>::New();
|
||||
points->SetDataType(VTK_DOUBLE);
|
||||
points->SetNumberOfPoints((vtkIdType)total);
|
||||
|
||||
tensors = vtkSmartPointer<vtkDoubleArray>::New();
|
||||
tensors->SetNumberOfComponents(9);
|
||||
tensors->SetNumberOfTuples((vtkIdType)total);
|
||||
|
||||
for(size_t i = 0; i < total; ++i, ++dpath)
|
||||
{
|
||||
Matx33d R = dpath->rotation().t(); // transposed because of
|
||||
tensors->SetTuple((vtkIdType)i, R.val); // column major order
|
||||
|
||||
Vec3d p = dpath->translation();
|
||||
points->SetPoint((vtkIdType)i, p.val);
|
||||
}
|
||||
}
|
||||
|
||||
cv::Mat cv::viz::vtkTrajectorySource::ExtractPoints(InputArray _traj)
|
||||
{
|
||||
CV_Assert(_traj.kind() == _InputArray::STD_VECTOR || _traj.kind() == _InputArray::MAT);
|
||||
CV_Assert(_traj.type() == CV_32FC(16) || _traj.type() == CV_64FC(16));
|
||||
|
||||
Mat points(1, (int)_traj.total(), CV_MAKETYPE(_traj.depth(), 3));
|
||||
const Affine3d* dpath = _traj.getMat().ptr<Affine3d>();
|
||||
const Affine3f* fpath = _traj.getMat().ptr<Affine3f>();
|
||||
|
||||
if (_traj.depth() == CV_32F)
|
||||
for(int i = 0; i < points.cols; ++i)
|
||||
points.at<Vec3f>(i) = fpath[i].translation();
|
||||
|
||||
if (_traj.depth() == CV_64F)
|
||||
for(int i = 0; i < points.cols; ++i)
|
||||
points.at<Vec3d>(i) = dpath[i].translation();
|
||||
|
||||
return points;
|
||||
}
|
||||
|
||||
int cv::viz::vtkTrajectorySource::RequestData(vtkInformation *vtkNotUsed(request), vtkInformationVector **vtkNotUsed(inputVector), vtkInformationVector *outputVector)
|
||||
{
|
||||
vtkInformation *outInfo = outputVector->GetInformationObject(0);
|
||||
vtkPolyData *output = vtkPolyData::SafeDownCast(outInfo->Get(vtkDataObject::DATA_OBJECT()));
|
||||
output->SetPoints(points);
|
||||
output->GetPointData()->SetTensors(tensors);
|
||||
return 1;
|
||||
}
|
|
@ -0,0 +1,84 @@
|
|||
/*M///////////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
|
||||
//
|
||||
// By downloading, copying, installing or using the software you agree to this license.
|
||||
// If you do not agree to this license, do not download, install,
|
||||
// copy or use the software.
|
||||
//
|
||||
//
|
||||
// License Agreement
|
||||
// For Open Source Computer Vision Library
|
||||
//
|
||||
// Copyright (C) 2013, OpenCV Foundation, all rights reserved.
|
||||
// Third party copyrights are property of their respective owners.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without modification,
|
||||
// are permitted provided that the following conditions are met:
|
||||
//
|
||||
// * Redistribution's of source code must retain the above copyright notice,
|
||||
// this list of conditions and the following disclaimer.
|
||||
//
|
||||
// * Redistribution's in binary form must reproduce the above copyright notice,
|
||||
// this list of conditions and the following disclaimer in the documentation
|
||||
// and/or other materials provided with the distribution.
|
||||
//
|
||||
// * The name of the copyright holders may not be used to endorse or promote products
|
||||
// derived from this software without specific prior written permission.
|
||||
//
|
||||
// This software is provided by the copyright holders and contributors "as is" and
|
||||
// any express or implied warranties, including, but not limited to, the implied
|
||||
// warranties of merchantability and fitness for a particular purpose are disclaimed.
|
||||
// In no event shall the Intel Corporation or contributors be liable for any direct,
|
||||
// indirect, incidental, special, exemplary, or consequential damages
|
||||
// (including, but not limited to, procurement of substitute goods or services;
|
||||
// loss of use, data, or profits; or business interruption) however caused
|
||||
// and on any theory of liability, whether in contract, strict liability,
|
||||
// or tort (including negligence or otherwise) arising in any way out of
|
||||
// the use of this software, even if advised of the possibility of such damage.
|
||||
//
|
||||
// Authors:
|
||||
// * Anatoly Baksheev, Itseez Inc. myname.mysurname <> mycompany.com
|
||||
//
|
||||
//M*/
|
||||
|
||||
#ifndef __vtkTrajectorySource_h
|
||||
#define __vtkTrajectorySource_h
|
||||
|
||||
#include <opencv2/core/mat.hpp>
|
||||
#include <vtkPolyDataAlgorithm.h>
|
||||
#include <vtkSmartPointer.h>
|
||||
#include <vtkPoints.h>
|
||||
#include <vtkCellArray.h>
|
||||
|
||||
namespace cv
|
||||
{
|
||||
namespace viz
|
||||
{
|
||||
class vtkTrajectorySource : public vtkPolyDataAlgorithm
|
||||
{
|
||||
public:
|
||||
static vtkTrajectorySource *New();
|
||||
vtkTypeMacro(vtkTrajectorySource,vtkPolyDataAlgorithm)
|
||||
|
||||
virtual void SetTrajectory(InputArray trajectory);
|
||||
|
||||
static Mat ExtractPoints(InputArray trajectory);
|
||||
|
||||
protected:
|
||||
vtkTrajectorySource();
|
||||
~vtkTrajectorySource();
|
||||
|
||||
vtkSmartPointer<vtkPoints> points;
|
||||
vtkSmartPointer<vtkDoubleArray> tensors;
|
||||
|
||||
int RequestData(vtkInformation *, vtkInformationVector **, vtkInformationVector *);
|
||||
private:
|
||||
vtkTrajectorySource(const vtkTrajectorySource&); // Not implemented.
|
||||
void operator=(const vtkTrajectorySource&); // Not implemented.
|
||||
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
|
@ -0,0 +1,169 @@
|
|||
/*M///////////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
|
||||
//
|
||||
// By downloading, copying, installing or using the software you agree to this license.
|
||||
// If you do not agree to this license, do not download, install,
|
||||
// copy or use the software.
|
||||
//
|
||||
//
|
||||
// License Agreement
|
||||
// For Open Source Computer Vision Library
|
||||
//
|
||||
// Copyright (C) 2013, OpenCV Foundation, all rights reserved.
|
||||
// Third party copyrights are property of their respective owners.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without modification,
|
||||
// are permitted provided that the following conditions are met:
|
||||
//
|
||||
// * Redistribution's of source code must retain the above copyright notice,
|
||||
// this list of conditions and the following disclaimer.
|
||||
//
|
||||
// * Redistribution's in binary form must reproduce the above copyright notice,
|
||||
// this list of conditions and the following disclaimer in the documentation
|
||||
// and/or other materials provided with the distribution.
|
||||
//
|
||||
// * The name of the copyright holders may not be used to endorse or promote products
|
||||
// derived from this software without specific prior written permission.
|
||||
//
|
||||
// This software is provided by the copyright holders and contributors "as is" and
|
||||
// any express or implied warranties, including, but not limited to, the implied
|
||||
// warranties of merchantability and fitness for a particular purpose are disclaimed.
|
||||
// In no event shall the Intel Corporation or contributors be liable for any direct,
|
||||
// indirect, incidental, special, exemplary, or consequential damages
|
||||
// (including, but not limited to, procurement of substitute goods or services;
|
||||
// loss of use, data, or profits; or business interruption) however caused
|
||||
// and on any theory of liability, whether in contract, strict liability,
|
||||
// or tort (including negligence or otherwise) arising in any way out of
|
||||
// the use of this software, even if advised of the possibility of such damage.
|
||||
//
|
||||
// Authors:
|
||||
// * Ozan Tonkal, ozantonkal@gmail.com
|
||||
// * Anatoly Baksheev, Itseez Inc. myname.mysurname <> mycompany.com
|
||||
//
|
||||
//M*/
|
||||
|
||||
#ifndef __OPENCV_VIZ_INTERACTOR_STYLE_H__
|
||||
#define __OPENCV_VIZ_INTERACTOR_STYLE_H__
|
||||
|
||||
#include <vtkInteractorStyle.h>
|
||||
|
||||
namespace cv
|
||||
{
|
||||
namespace viz
|
||||
{
|
||||
class vtkVizInteractorStyle : public vtkInteractorStyle
|
||||
{
|
||||
public:
|
||||
static vtkVizInteractorStyle *New();
|
||||
vtkTypeMacro(vtkVizInteractorStyle, vtkInteractorStyle)
|
||||
void PrintSelf(ostream& os, vtkIndent indent);
|
||||
|
||||
virtual void OnChar();
|
||||
virtual void OnKeyDown();
|
||||
virtual void OnKeyUp();
|
||||
|
||||
virtual void OnMouseMove();
|
||||
virtual void OnLeftButtonDown();
|
||||
virtual void OnLeftButtonUp();
|
||||
virtual void OnMiddleButtonDown();
|
||||
virtual void OnMiddleButtonUp();
|
||||
virtual void OnRightButtonDown();
|
||||
virtual void OnRightButtonUp();
|
||||
virtual void OnMouseWheelForward();
|
||||
virtual void OnMouseWheelBackward();
|
||||
virtual void OnTimer();
|
||||
|
||||
virtual void Rotate();
|
||||
virtual void Spin();
|
||||
virtual void Pan();
|
||||
virtual void Dolly();
|
||||
|
||||
vtkSetMacro(FlyMode,bool)
|
||||
vtkGetMacro(FlyMode,bool)
|
||||
|
||||
|
||||
vtkSetMacro(MotionFactor, double)
|
||||
vtkGetMacro(MotionFactor, double)
|
||||
|
||||
void registerMouseCallback(void (*callback)(const MouseEvent&, void*), void* cookie = 0);
|
||||
void registerKeyboardCallback(void (*callback)(const KeyboardEvent&, void*), void * cookie = 0);
|
||||
|
||||
void setWidgetActorMap(const Ptr<WidgetActorMap>& actors) { widget_actor_map_ = actors; }
|
||||
void saveScreenshot(const String &file);
|
||||
void exportScene(const String &file);
|
||||
void exportScene();
|
||||
void changePointsSize(float delta);
|
||||
void setRepresentationToPoints();
|
||||
void printCameraParams();
|
||||
void toggleFullScreen();
|
||||
void resetViewerPose();
|
||||
void toggleStereo();
|
||||
void printHelp();
|
||||
|
||||
// Set the basic unit step size : by default 1/250 of bounding diagonal
|
||||
vtkSetMacro(MotionStepSize,double)
|
||||
vtkGetMacro(MotionStepSize,double)
|
||||
|
||||
// Set acceleration factor when shift key is applied : default 10
|
||||
vtkSetMacro(MotionAccelerationFactor,double)
|
||||
vtkGetMacro(MotionAccelerationFactor,double)
|
||||
|
||||
// Set the basic angular unit for turning : default 1 degree
|
||||
vtkSetMacro(AngleStepSize,double)
|
||||
vtkGetMacro(AngleStepSize,double)
|
||||
|
||||
private:
|
||||
Ptr<WidgetActorMap> widget_actor_map_;
|
||||
|
||||
Vec2i win_size_;
|
||||
Vec2i win_pos_;
|
||||
Vec2i max_win_size_;
|
||||
|
||||
void zoomIn();
|
||||
void zoomOut();
|
||||
|
||||
protected:
|
||||
vtkVizInteractorStyle();
|
||||
~vtkVizInteractorStyle();
|
||||
|
||||
virtual void Dolly(double factor);
|
||||
|
||||
void Fly();
|
||||
void FlyByMouse();
|
||||
void FlyByKey();
|
||||
void SetupMotionVars();
|
||||
void MotionAlongVector(const Vec3d& vector, double amount, vtkCamera* cam);
|
||||
|
||||
private:
|
||||
vtkVizInteractorStyle(const vtkVizInteractorStyle&);
|
||||
vtkVizInteractorStyle& operator=(const vtkVizInteractorStyle&);
|
||||
|
||||
//! True for red-blue colors, false for magenta-green.
|
||||
bool stereo_anaglyph_redblue_;
|
||||
|
||||
void (*keyboardCallback_)(const KeyboardEvent&, void*);
|
||||
void *keyboard_callback_cookie_;
|
||||
|
||||
void (*mouseCallback_)(const MouseEvent&, void*);
|
||||
void *mouse_callback_cookie_;
|
||||
|
||||
bool FlyMode;
|
||||
double MotionFactor;
|
||||
|
||||
int getModifiers();
|
||||
|
||||
// from fly
|
||||
unsigned char KeysDown;
|
||||
double DiagonalLength;
|
||||
double MotionStepSize;
|
||||
double MotionUserScale;
|
||||
double MotionAccelerationFactor;
|
||||
double AngleStepSize;
|
||||
double DeltaYaw;
|
||||
double DeltaPitch;
|
||||
};
|
||||
} // end namespace viz
|
||||
} // end namespace cv
|
||||
|
||||
#endif
|
|
@ -0,0 +1,107 @@
|
|||
/*M///////////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
|
||||
//
|
||||
// By downloading, copying, installing or using the software you agree to this license.
|
||||
// If you do not agree to this license, do not download, install,
|
||||
// copy or use the software.
|
||||
//
|
||||
//
|
||||
// License Agreement
|
||||
// For Open Source Computer Vision Library
|
||||
//
|
||||
// Copyright (C) 2013, OpenCV Foundation, all rights reserved.
|
||||
// Third party copyrights are property of their respective owners.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without modification,
|
||||
// are permitted provided that the following conditions are met:
|
||||
//
|
||||
// * Redistribution's of source code must retain the above copyright notice,
|
||||
// this list of conditions and the following disclaimer.
|
||||
//
|
||||
// * Redistribution's in binary form must reproduce the above copyright notice,
|
||||
// this list of conditions and the following disclaimer in the documentation
|
||||
// and/or other materials provided with the distribution.
|
||||
//
|
||||
// * The name of the copyright holders may not be used to endorse or promote products
|
||||
// derived from this software without specific prior written permission.
|
||||
//
|
||||
// This software is provided by the copyright holders and contributors "as is" and
|
||||
// any express or implied warranties, including, but not limited to, the implied
|
||||
// warranties of merchantability and fitness for a particular purpose are disclaimed.
|
||||
// In no event shall the Intel Corporation or contributors be liable for any direct,
|
||||
// indirect, incidental, special, exemplary, or consequential damages
|
||||
// (including, but not limited to, procurement of substitute goods or services;
|
||||
// loss of use, data, or profits; or business interruption) however caused
|
||||
// and on any theory of liability, whether in contract, strict liability,
|
||||
// or tort (including negligence or otherwise) arising in any way out of
|
||||
// the use of this software, even if advised of the possibility of such damage.
|
||||
//
|
||||
// Authors:
|
||||
// * Anatoly Baksheev, Itseez Inc. myname.mysurname <> mycompany.com
|
||||
//
|
||||
//M*/
|
||||
|
||||
#include "../precomp.hpp"
|
||||
|
||||
namespace cv { namespace viz
|
||||
{
|
||||
vtkStandardNewMacro(vtkXYZReader);
|
||||
}}
|
||||
|
||||
|
||||
cv::viz::vtkXYZReader::vtkXYZReader()
|
||||
{
|
||||
this->FileName = 0;
|
||||
this->SetNumberOfInputPorts(0);
|
||||
}
|
||||
|
||||
cv::viz::vtkXYZReader::~vtkXYZReader()
|
||||
{
|
||||
this->SetFileName(0);
|
||||
}
|
||||
|
||||
void cv::viz::vtkXYZReader::PrintSelf(ostream& os, vtkIndent indent)
|
||||
{
|
||||
this->Superclass::PrintSelf(os,indent);
|
||||
os << indent << "FileName: " << (this->FileName ? this->FileName : "(none)") << "\n";
|
||||
}
|
||||
|
||||
int cv::viz::vtkXYZReader::RequestData(vtkInformation*, vtkInformationVector**, vtkInformationVector* outputVector)
|
||||
{
|
||||
// Make sure we have a file to read.
|
||||
if(!this->FileName)
|
||||
{
|
||||
vtkErrorMacro("A FileName must be specified.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Open the input file.
|
||||
std::ifstream fin(this->FileName);
|
||||
if(!fin)
|
||||
{
|
||||
vtkErrorMacro("Error opening file " << this->FileName);
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Allocate objects to hold points and vertex cells.
|
||||
vtkSmartPointer<vtkPoints> points = vtkSmartPointer<vtkPoints>::New();
|
||||
vtkSmartPointer<vtkCellArray> verts = vtkSmartPointer<vtkCellArray>::New();
|
||||
|
||||
// Read points from the file.
|
||||
vtkDebugMacro("Reading points from file " << this->FileName);
|
||||
double x[3];
|
||||
while(fin >> x[0] >> x[1] >> x[2])
|
||||
{
|
||||
vtkIdType id = points->InsertNextPoint(x);
|
||||
verts->InsertNextCell(1, &id);
|
||||
}
|
||||
vtkDebugMacro("Read " << points->GetNumberOfPoints() << " points.");
|
||||
|
||||
// Store the points and cells in the output data object.
|
||||
vtkPolyData* output = vtkPolyData::GetData(outputVector);
|
||||
output->SetPoints(points);
|
||||
output->SetVerts(verts);
|
||||
|
||||
return 1;
|
||||
}
|
|
@ -0,0 +1,80 @@
|
|||
/*M///////////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
|
||||
//
|
||||
// By downloading, copying, installing or using the software you agree to this license.
|
||||
// If you do not agree to this license, do not download, install,
|
||||
// copy or use the software.
|
||||
//
|
||||
//
|
||||
// License Agreement
|
||||
// For Open Source Computer Vision Library
|
||||
//
|
||||
// Copyright (C) 2013, OpenCV Foundation, all rights reserved.
|
||||
// Third party copyrights are property of their respective owners.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without modification,
|
||||
// are permitted provided that the following conditions are met:
|
||||
//
|
||||
// * Redistribution's of source code must retain the above copyright notice,
|
||||
// this list of conditions and the following disclaimer.
|
||||
//
|
||||
// * Redistribution's in binary form must reproduce the above copyright notice,
|
||||
// this list of conditions and the following disclaimer in the documentation
|
||||
// and/or other materials provided with the distribution.
|
||||
//
|
||||
// * The name of the copyright holders may not be used to endorse or promote products
|
||||
// derived from this software without specific prior written permission.
|
||||
//
|
||||
// This software is provided by the copyright holders and contributors "as is" and
|
||||
// any express or implied warranties, including, but not limited to, the implied
|
||||
// warranties of merchantability and fitness for a particular purpose are disclaimed.
|
||||
// In no event shall the Intel Corporation or contributors be liable for any direct,
|
||||
// indirect, incidental, special, exemplary, or consequential damages
|
||||
// (including, but not limited to, procurement of substitute goods or services;
|
||||
// loss of use, data, or profits; or business interruption) however caused
|
||||
// and on any theory of liability, whether in contract, strict liability,
|
||||
// or tort (including negligence or otherwise) arising in any way out of
|
||||
// the use of this software, even if advised of the possibility of such damage.
|
||||
//
|
||||
// Authors:
|
||||
// * Anatoly Baksheev, Itseez Inc. myname.mysurname <> mycompany.com
|
||||
//
|
||||
//M*/
|
||||
|
||||
#ifndef __vtkXYZReader_h
|
||||
#define __vtkXYZReader_h
|
||||
|
||||
#include "vtkPolyDataAlgorithm.h"
|
||||
|
||||
namespace cv
|
||||
{
|
||||
namespace viz
|
||||
{
|
||||
class vtkXYZReader : public vtkPolyDataAlgorithm
|
||||
{
|
||||
public:
|
||||
static vtkXYZReader* New();
|
||||
vtkTypeMacro(vtkXYZReader,vtkPolyDataAlgorithm)
|
||||
void PrintSelf(ostream& os, vtkIndent indent);
|
||||
|
||||
// Description:
|
||||
// Set/Get the name of the file from which to read points.
|
||||
vtkSetStringMacro(FileName)
|
||||
vtkGetStringMacro(FileName)
|
||||
|
||||
protected:
|
||||
vtkXYZReader();
|
||||
~vtkXYZReader();
|
||||
|
||||
char* FileName;
|
||||
|
||||
int RequestData(vtkInformation*, vtkInformationVector**, vtkInformationVector*);
|
||||
private:
|
||||
vtkXYZReader(const vtkXYZReader&); // Not implemented.
|
||||
void operator=(const vtkXYZReader&); // Not implemented.
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
|
@ -0,0 +1,122 @@
|
|||
/*M///////////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
|
||||
//
|
||||
// By downloading, copying, installing or using the software you agree to this license.
|
||||
// If you do not agree to this license, do not download, install,
|
||||
// copy or use the software.
|
||||
//
|
||||
//
|
||||
// License Agreement
|
||||
// For Open Source Computer Vision Library
|
||||
//
|
||||
// Copyright (C) 2013, OpenCV Foundation, all rights reserved.
|
||||
// Third party copyrights are property of their respective owners.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without modification,
|
||||
// are permitted provided that the following conditions are met:
|
||||
//
|
||||
// * Redistribution's of source code must retain the above copyright notice,
|
||||
// this list of conditions and the following disclaimer.
|
||||
//
|
||||
// * Redistribution's in binary form must reproduce the above copyright notice,
|
||||
// this list of conditions and the following disclaimer in the documentation
|
||||
// and/or other materials provided with the distribution.
|
||||
//
|
||||
// * The name of the copyright holders may not be used to endorse or promote products
|
||||
// derived from this software without specific prior written permission.
|
||||
//
|
||||
// This software is provided by the copyright holders and contributors "as is" and
|
||||
// any express or implied warranties, including, but not limited to, the implied
|
||||
// warranties of merchantability and fitness for a particular purpose are disclaimed.
|
||||
// In no event shall the Intel Corporation or contributors be liable for any direct,
|
||||
// indirect, incidental, special, exemplary, or consequential damages
|
||||
// (including, but not limited to, procurement of substitute goods or services;
|
||||
// loss of use, data, or profits; or business interruption) however caused
|
||||
// and on any theory of liability, whether in contract, strict liability,
|
||||
// or tort (including negligence or otherwise) arising in any way out of
|
||||
// the use of this software, even if advised of the possibility of such damage.
|
||||
//
|
||||
// Authors:
|
||||
// * Anatoly Baksheev, Itseez Inc. myname.mysurname <> mycompany.com
|
||||
//
|
||||
//M*/
|
||||
|
||||
#include "../precomp.hpp"
|
||||
|
||||
namespace cv { namespace viz
|
||||
{
|
||||
vtkStandardNewMacro(vtkXYZWriter);
|
||||
}}
|
||||
|
||||
cv::viz::vtkXYZWriter::vtkXYZWriter()
|
||||
{
|
||||
std::ofstream fout; // only used to extract the default precision
|
||||
this->DecimalPrecision = fout.precision();
|
||||
}
|
||||
|
||||
void cv::viz::vtkXYZWriter::WriteData()
|
||||
{
|
||||
vtkPolyData *input = this->GetInput();
|
||||
if (!input)
|
||||
return;
|
||||
|
||||
if (!this->FileName )
|
||||
{
|
||||
vtkErrorMacro(<< "No FileName specified! Can't write!");
|
||||
this->SetErrorCode(vtkErrorCode::NoFileNameError);
|
||||
return;
|
||||
}
|
||||
|
||||
vtkDebugMacro(<<"Opening vtk file for writing...");
|
||||
std::ostream *outfilep = new std::ofstream(this->FileName, ios::out);
|
||||
if (outfilep->fail())
|
||||
{
|
||||
vtkErrorMacro(<< "Unable to open file: "<< this->FileName);
|
||||
this->SetErrorCode(vtkErrorCode::CannotOpenFileError);
|
||||
delete outfilep;
|
||||
return;
|
||||
}
|
||||
|
||||
ostream &outfile = *outfilep;
|
||||
|
||||
for(vtkIdType i = 0; i < input->GetNumberOfPoints(); ++i)
|
||||
{
|
||||
Vec3d p;
|
||||
input->GetPoint(i, p.val);
|
||||
outfile << std::setprecision(this->DecimalPrecision) << p[0] << " " << p[1] << " " << p[2] << std::endl;
|
||||
}
|
||||
|
||||
// Close the file
|
||||
vtkDebugMacro(<<"Closing vtk file\n");
|
||||
delete outfilep;
|
||||
|
||||
// Delete the file if an error occurred
|
||||
if (this->ErrorCode == vtkErrorCode::OutOfDiskSpaceError)
|
||||
{
|
||||
vtkErrorMacro("Ran out of disk space; deleting file: " << this->FileName);
|
||||
unlink(this->FileName);
|
||||
}
|
||||
}
|
||||
|
||||
int cv::viz::vtkXYZWriter::FillInputPortInformation(int, vtkInformation *info)
|
||||
{
|
||||
info->Set(vtkAlgorithm::INPUT_REQUIRED_DATA_TYPE(), "vtkPolyData");
|
||||
return 1;
|
||||
}
|
||||
|
||||
void cv::viz::vtkXYZWriter::PrintSelf(ostream& os, vtkIndent indent)
|
||||
{
|
||||
this->Superclass::PrintSelf(os,indent);
|
||||
os << indent << "DecimalPrecision: " << this->DecimalPrecision << "\n";
|
||||
}
|
||||
|
||||
vtkPolyData* cv::viz::vtkXYZWriter::GetInput()
|
||||
{
|
||||
return vtkPolyData::SafeDownCast(this->Superclass::GetInput());
|
||||
}
|
||||
|
||||
vtkPolyData* cv::viz::vtkXYZWriter::GetInput(int port)
|
||||
{
|
||||
return vtkPolyData::SafeDownCast(this->Superclass::GetInput(port));
|
||||
}
|
|
@ -0,0 +1,90 @@
|
|||
/*M///////////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
|
||||
//
|
||||
// By downloading, copying, installing or using the software you agree to this license.
|
||||
// If you do not agree to this license, do not download, install,
|
||||
// copy or use the software.
|
||||
//
|
||||
//
|
||||
// License Agreement
|
||||
// For Open Source Computer Vision Library
|
||||
//
|
||||
// Copyright (C) 2013, OpenCV Foundation, all rights reserved.
|
||||
// Third party copyrights are property of their respective owners.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without modification,
|
||||
// are permitted provided that the following conditions are met:
|
||||
//
|
||||
// * Redistribution's of source code must retain the above copyright notice,
|
||||
// this list of conditions and the following disclaimer.
|
||||
//
|
||||
// * Redistribution's in binary form must reproduce the above copyright notice,
|
||||
// this list of conditions and the following disclaimer in the documentation
|
||||
// and/or other materials provided with the distribution.
|
||||
//
|
||||
// * The name of the copyright holders may not be used to endorse or promote products
|
||||
// derived from this software without specific prior written permission.
|
||||
//
|
||||
// This software is provided by the copyright holders and contributors "as is" and
|
||||
// any express or implied warranties, including, but not limited to, the implied
|
||||
// warranties of merchantability and fitness for a particular purpose are disclaimed.
|
||||
// In no event shall the Intel Corporation or contributors be liable for any direct,
|
||||
// indirect, incidental, special, exemplary, or consequential damages
|
||||
// (including, but not limited to, procurement of substitute goods or services;
|
||||
// loss of use, data, or profits; or business interruption) however caused
|
||||
// and on any theory of liability, whether in contract, strict liability,
|
||||
// or tort (including negligence or otherwise) arising in any way out of
|
||||
// the use of this software, even if advised of the possibility of such damage.
|
||||
//
|
||||
// Authors:
|
||||
// * Anatoly Baksheev, Itseez Inc. myname.mysurname <> mycompany.com
|
||||
//
|
||||
//M*/
|
||||
|
||||
#ifndef __vtkXYZWriter_h
|
||||
#define __vtkXYZWriter_h
|
||||
|
||||
#include "vtkWriter.h"
|
||||
|
||||
namespace cv
|
||||
{
|
||||
namespace viz
|
||||
{
|
||||
class vtkXYZWriter : public vtkWriter
|
||||
{
|
||||
public:
|
||||
static vtkXYZWriter *New();
|
||||
vtkTypeMacro(vtkXYZWriter,vtkWriter)
|
||||
void PrintSelf(ostream& os, vtkIndent indent);
|
||||
|
||||
vtkGetMacro(DecimalPrecision, int)
|
||||
vtkSetMacro(DecimalPrecision, int)
|
||||
|
||||
// Description:
|
||||
// Specify file name of data file to write.
|
||||
vtkSetStringMacro(FileName)
|
||||
vtkGetStringMacro(FileName)
|
||||
|
||||
// Description:
|
||||
// Get the input to this writer.
|
||||
vtkPolyData* GetInput();
|
||||
vtkPolyData* GetInput(int port);
|
||||
|
||||
protected:
|
||||
vtkXYZWriter();
|
||||
~vtkXYZWriter(){}
|
||||
|
||||
void WriteData();
|
||||
int FillInputPortInformation(int port, vtkInformation *info);
|
||||
|
||||
int DecimalPrecision;
|
||||
char *FileName;
|
||||
|
||||
private:
|
||||
vtkXYZWriter(const vtkXYZWriter&); // Not implemented.
|
||||
void operator=(const vtkXYZWriter&); // Not implemented.
|
||||
};
|
||||
}
|
||||
}
|
||||
#endif
|
|
@ -0,0 +1,352 @@
|
|||
/*M///////////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
|
||||
//
|
||||
// By downloading, copying, installing or using the software you agree to this license.
|
||||
// If you do not agree to this license, do not download, install,
|
||||
// copy or use the software.
|
||||
//
|
||||
//
|
||||
// License Agreement
|
||||
// For Open Source Computer Vision Library
|
||||
//
|
||||
// Copyright (C) 2013, OpenCV Foundation, all rights reserved.
|
||||
// Third party copyrights are property of their respective owners.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without modification,
|
||||
// are permitted provided that the following conditions are met:
|
||||
//
|
||||
// * Redistribution's of source code must retain the above copyright notice,
|
||||
// this list of conditions and the following disclaimer.
|
||||
//
|
||||
// * Redistribution's in binary form must reproduce the above copyright notice,
|
||||
// this list of conditions and the following disclaimer in the documentation
|
||||
// and/or other materials provided with the distribution.
|
||||
//
|
||||
// * The name of the copyright holders may not be used to endorse or promote products
|
||||
// derived from this software without specific prior written permission.
|
||||
//
|
||||
// This software is provided by the copyright holders and contributors "as is" and
|
||||
// any express or implied warranties, including, but not limited to, the implied
|
||||
// warranties of merchantability and fitness for a particular purpose are disclaimed.
|
||||
// In no event shall the Intel Corporation or contributors be liable for any direct,
|
||||
// indirect, incidental, special, exemplary, or consequential damages
|
||||
// (including, but not limited to, procurement of substitute goods or services;
|
||||
// loss of use, data, or profits; or business interruption) however caused
|
||||
// and on any theory of liability, whether in contract, strict liability,
|
||||
// or tort (including negligence or otherwise) arising in any way out of
|
||||
// the use of this software, even if advised of the possibility of such damage.
|
||||
//
|
||||
// Authors:
|
||||
// * Ozan Tonkal, ozantonkal@gmail.com
|
||||
// * Anatoly Baksheev, Itseez Inc. myname.mysurname <> mycompany.com
|
||||
//
|
||||
//M*/
|
||||
|
||||
#include "precomp.hpp"
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////
|
||||
/// widget implementation
|
||||
|
||||
class cv::viz::Widget::Impl
|
||||
{
|
||||
public:
|
||||
vtkSmartPointer<vtkProp> prop;
|
||||
Impl() : prop(0) {}
|
||||
};
|
||||
|
||||
cv::viz::Widget::Widget() : impl_( new Impl() ) { }
|
||||
|
||||
cv::viz::Widget::Widget(const Widget& other) : impl_( new Impl() )
|
||||
{
|
||||
if (other.impl_ && other.impl_->prop)
|
||||
impl_->prop = other.impl_->prop;
|
||||
}
|
||||
|
||||
cv::viz::Widget& cv::viz::Widget::operator=(const Widget& other)
|
||||
{
|
||||
if (!impl_)
|
||||
impl_ = new Impl();
|
||||
|
||||
if (other.impl_)
|
||||
impl_->prop = other.impl_->prop;
|
||||
return *this;
|
||||
}
|
||||
|
||||
cv::viz::Widget::~Widget()
|
||||
{
|
||||
if (impl_)
|
||||
{
|
||||
delete impl_;
|
||||
impl_ = 0;
|
||||
}
|
||||
}
|
||||
|
||||
cv::viz::Widget cv::viz::Widget::fromPlyFile(const String &file_name)
|
||||
{
|
||||
CV_Assert(vtkPLYReader::CanReadFile(file_name.c_str()));
|
||||
|
||||
vtkSmartPointer<vtkPLYReader> reader = vtkSmartPointer<vtkPLYReader>::New();
|
||||
reader->SetFileName(file_name.c_str());
|
||||
|
||||
vtkSmartPointer<vtkDataSetMapper> mapper = vtkSmartPointer<vtkDataSetMapper>::New();
|
||||
mapper->SetInputConnection( reader->GetOutputPort() );
|
||||
#if VTK_MAJOR_VERSION < 8
|
||||
mapper->ImmediateModeRenderingOff();
|
||||
#endif
|
||||
|
||||
vtkSmartPointer<vtkActor> actor = vtkSmartPointer<vtkActor>::New();
|
||||
actor->GetProperty()->SetInterpolationToFlat();
|
||||
actor->GetProperty()->BackfaceCullingOn();
|
||||
actor->SetMapper(mapper);
|
||||
|
||||
Widget widget;
|
||||
WidgetAccessor::setProp(widget, actor);
|
||||
return widget;
|
||||
}
|
||||
|
||||
void cv::viz::Widget::setRenderingProperty(int property, double value)
|
||||
{
|
||||
vtkActor *actor = vtkActor::SafeDownCast(WidgetAccessor::getProp(*this));
|
||||
CV_Assert("Widget type is not supported." && actor);
|
||||
|
||||
switch (property)
|
||||
{
|
||||
case POINT_SIZE: actor->GetProperty()->SetPointSize(float(value)); break;
|
||||
case OPACITY: actor->GetProperty()->SetOpacity(value); break;
|
||||
case LINE_WIDTH: actor->GetProperty()->SetLineWidth(float(value)); break;
|
||||
#if VTK_MAJOR_VERSION < 8
|
||||
case IMMEDIATE_RENDERING: actor->GetMapper()->SetImmediateModeRendering(int(value)); break;
|
||||
#else
|
||||
case IMMEDIATE_RENDERING: std::cerr << "this property has no effect" << std::endl; break;
|
||||
#endif
|
||||
case AMBIENT: actor->GetProperty()->SetAmbient(float(value)); break;
|
||||
case LIGHTING:
|
||||
{
|
||||
if (value == 0)
|
||||
actor->GetProperty()->LightingOff();
|
||||
else
|
||||
actor->GetProperty()->LightingOn();
|
||||
break;
|
||||
}
|
||||
case FONT_SIZE:
|
||||
{
|
||||
vtkTextActor* text_actor = vtkTextActor::SafeDownCast(actor);
|
||||
CV_Assert("Widget does not have text content." && text_actor);
|
||||
text_actor->GetTextProperty()->SetFontSize(int(value));
|
||||
break;
|
||||
}
|
||||
case REPRESENTATION:
|
||||
{
|
||||
switch (int(value))
|
||||
{
|
||||
case REPRESENTATION_POINTS: actor->GetProperty()->SetRepresentationToPoints(); break;
|
||||
case REPRESENTATION_WIREFRAME: actor->GetProperty()->SetRepresentationToWireframe(); break;
|
||||
case REPRESENTATION_SURFACE: actor->GetProperty()->SetRepresentationToSurface(); break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case SHADING:
|
||||
{
|
||||
switch (int(value))
|
||||
{
|
||||
case SHADING_FLAT: actor->GetProperty()->SetInterpolationToFlat(); break;
|
||||
case SHADING_GOURAUD:
|
||||
{
|
||||
if (!actor->GetMapper()->GetInput()->GetPointData()->GetNormals())
|
||||
{
|
||||
vtkSmartPointer<vtkPolyDataMapper> mapper = vtkPolyDataMapper::SafeDownCast(actor->GetMapper());
|
||||
CV_Assert("Can't set shading property for such type of widget" && mapper);
|
||||
|
||||
vtkSmartPointer<vtkPolyData> with_normals = VtkUtils::ComputeNormals(mapper->GetInput());
|
||||
VtkUtils::SetInputData(mapper, with_normals);
|
||||
}
|
||||
actor->GetProperty()->SetInterpolationToGouraud();
|
||||
break;
|
||||
}
|
||||
case SHADING_PHONG:
|
||||
{
|
||||
if (!actor->GetMapper()->GetInput()->GetPointData()->GetNormals())
|
||||
{
|
||||
vtkSmartPointer<vtkPolyDataMapper> mapper = vtkPolyDataMapper::SafeDownCast(actor->GetMapper());
|
||||
CV_Assert("Can't set shading property for such type of widget" && mapper);
|
||||
|
||||
vtkSmartPointer<vtkPolyData> with_normals = VtkUtils::ComputeNormals(mapper->GetInput());
|
||||
VtkUtils::SetInputData(mapper, with_normals);
|
||||
}
|
||||
actor->GetProperty()->SetInterpolationToPhong();
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
CV_Assert("setRenderingProperty: Unknown property");
|
||||
}
|
||||
actor->Modified();
|
||||
}
|
||||
|
||||
double cv::viz::Widget::getRenderingProperty(int property) const
|
||||
{
|
||||
vtkActor *actor = vtkActor::SafeDownCast(WidgetAccessor::getProp(*this));
|
||||
CV_Assert("Widget type is not supported." && actor);
|
||||
|
||||
double value = 0.0;
|
||||
switch (property)
|
||||
{
|
||||
case POINT_SIZE: value = actor->GetProperty()->GetPointSize(); break;
|
||||
case OPACITY: value = actor->GetProperty()->GetOpacity(); break;
|
||||
case LINE_WIDTH: value = actor->GetProperty()->GetLineWidth(); break;
|
||||
#if VTK_MAJOR_VERSION < 8
|
||||
case IMMEDIATE_RENDERING: value = actor->GetMapper()->GetImmediateModeRendering(); break;
|
||||
#else
|
||||
case IMMEDIATE_RENDERING: std::cerr << "this property has no effect" << std::endl; break;
|
||||
#endif
|
||||
case AMBIENT: value = actor->GetProperty()->GetAmbient(); break;
|
||||
case LIGHTING: value = actor->GetProperty()->GetLighting(); break;
|
||||
case FONT_SIZE:
|
||||
{
|
||||
vtkTextActor* text_actor = vtkTextActor::SafeDownCast(actor);
|
||||
CV_Assert("Widget does not have text content." && text_actor);
|
||||
value = text_actor->GetTextProperty()->GetFontSize();;
|
||||
break;
|
||||
}
|
||||
case REPRESENTATION:
|
||||
{
|
||||
switch (actor->GetProperty()->GetRepresentation())
|
||||
{
|
||||
case VTK_POINTS: value = REPRESENTATION_POINTS; break;
|
||||
case VTK_WIREFRAME: value = REPRESENTATION_WIREFRAME; break;
|
||||
case VTK_SURFACE: value = REPRESENTATION_SURFACE; break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case SHADING:
|
||||
{
|
||||
switch (actor->GetProperty()->GetInterpolation())
|
||||
{
|
||||
case VTK_FLAT: value = SHADING_FLAT; break;
|
||||
case VTK_GOURAUD: value = SHADING_GOURAUD; break;
|
||||
case VTK_PHONG: value = SHADING_PHONG; break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
CV_Assert("getRenderingProperty: Unknown property");
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////
|
||||
/// widget accessor implementation
|
||||
|
||||
vtkSmartPointer<vtkProp> cv::viz::WidgetAccessor::getProp(const Widget& widget)
|
||||
{
|
||||
return widget.impl_->prop;
|
||||
}
|
||||
|
||||
void cv::viz::WidgetAccessor::setProp(Widget& widget, vtkSmartPointer<vtkProp> prop)
|
||||
{
|
||||
widget.impl_->prop = prop;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////
|
||||
/// widget3D implementation
|
||||
|
||||
void cv::viz::Widget3D::setPose(const Affine3d &pose)
|
||||
{
|
||||
vtkProp3D *actor = vtkProp3D::SafeDownCast(WidgetAccessor::getProp(*this));
|
||||
CV_Assert("Widget is not 3D." && actor);
|
||||
|
||||
vtkSmartPointer<vtkMatrix4x4> matrix = vtkmatrix(pose.matrix);
|
||||
actor->SetUserMatrix(matrix);
|
||||
actor->Modified();
|
||||
}
|
||||
|
||||
void cv::viz::Widget3D::updatePose(const Affine3d &pose)
|
||||
{
|
||||
vtkProp3D *actor = vtkProp3D::SafeDownCast(WidgetAccessor::getProp(*this));
|
||||
CV_Assert("Widget is not 3D." && actor);
|
||||
|
||||
vtkSmartPointer<vtkMatrix4x4> matrix = actor->GetUserMatrix();
|
||||
if (!matrix)
|
||||
{
|
||||
setPose(pose);
|
||||
return;
|
||||
}
|
||||
|
||||
Affine3d updated_pose = pose * Affine3d(*matrix->Element);
|
||||
matrix = vtkmatrix(updated_pose.matrix);
|
||||
|
||||
actor->SetUserMatrix(matrix);
|
||||
actor->Modified();
|
||||
}
|
||||
|
||||
cv::Affine3d cv::viz::Widget3D::getPose() const
|
||||
{
|
||||
vtkProp3D *actor = vtkProp3D::SafeDownCast(WidgetAccessor::getProp(*this));
|
||||
CV_Assert("Widget is not 3D." && actor);
|
||||
if (!actor->GetUserMatrix())
|
||||
{
|
||||
return Affine3d(); // empty user matrix, return an identity transform.
|
||||
}
|
||||
return Affine3d(*actor->GetUserMatrix()->Element);
|
||||
}
|
||||
|
||||
void cv::viz::Widget3D::applyTransform(const Affine3d &transform)
|
||||
{
|
||||
vtkActor *actor = vtkActor::SafeDownCast(WidgetAccessor::getProp(*this));
|
||||
CV_Assert("Widget is not 3D actor." && actor);
|
||||
|
||||
vtkSmartPointer<vtkPolyDataMapper> mapper = vtkPolyDataMapper::SafeDownCast(actor->GetMapper());
|
||||
CV_Assert("Widget doesn't have a polydata mapper" && mapper);
|
||||
|
||||
mapper->Update(); // #10945
|
||||
VtkUtils::SetInputData(mapper, VtkUtils::TransformPolydata(mapper->GetInput(), transform));
|
||||
mapper->Update();
|
||||
}
|
||||
|
||||
void cv::viz::Widget3D::setColor(const Color &color)
|
||||
{
|
||||
// Cast to actor instead of prop3d since prop3d doesn't provide getproperty
|
||||
vtkActor *actor = vtkActor::SafeDownCast(WidgetAccessor::getProp(*this));
|
||||
CV_Assert("Widget type is not supported." && actor);
|
||||
|
||||
Color c = vtkcolor(color);
|
||||
actor->GetMapper()->ScalarVisibilityOff();
|
||||
actor->GetProperty()->SetColor(c.val);
|
||||
actor->GetProperty()->SetEdgeColor(c.val);
|
||||
actor->Modified();
|
||||
}
|
||||
|
||||
template<> cv::viz::Widget3D cv::viz::Widget::cast<cv::viz::Widget3D>() const
|
||||
{
|
||||
vtkProp3D *actor = vtkProp3D::SafeDownCast(WidgetAccessor::getProp(*this));
|
||||
CV_Assert("Widget cannot be cast." && actor);
|
||||
|
||||
Widget3D widget;
|
||||
WidgetAccessor::setProp(widget, actor);
|
||||
return widget;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////
|
||||
/// widget2D implementation
|
||||
|
||||
void cv::viz::Widget2D::setColor(const Color &color)
|
||||
{
|
||||
vtkActor2D *actor = vtkActor2D::SafeDownCast(WidgetAccessor::getProp(*this));
|
||||
CV_Assert("Widget type is not supported." && actor);
|
||||
Color c = vtkcolor(color);
|
||||
actor->GetProperty()->SetColor(c.val);
|
||||
actor->Modified();
|
||||
}
|
||||
|
||||
template<> cv::viz::Widget2D cv::viz::Widget::cast<cv::viz::Widget2D>() const
|
||||
{
|
||||
vtkActor2D *actor = vtkActor2D::SafeDownCast(WidgetAccessor::getProp(*this));
|
||||
CV_Assert("Widget cannot be cast." && actor);
|
||||
|
||||
Widget2D widget;
|
||||
WidgetAccessor::setProp(widget, actor);
|
||||
return widget;
|
||||
}
|
|
@ -0,0 +1,27 @@
|
|||
// This file is part of OpenCV project.
|
||||
// It is subject to the license terms in the LICENSE file found in the top-level directory
|
||||
// of this distribution and at http://opencv.org/license.html.
|
||||
#include "test_precomp.hpp"
|
||||
|
||||
cv::String cv::Path::combine(const String& item1, const String& item2)
|
||||
{
|
||||
if (item1.empty())
|
||||
return item2;
|
||||
|
||||
if (item2.empty())
|
||||
return item1;
|
||||
|
||||
char last = item1[item1.size()-1];
|
||||
|
||||
bool need_append = last != '/' && last != '\\';
|
||||
return item1 + (need_append ? "/" : "") + item2;
|
||||
}
|
||||
|
||||
cv::String cv::Path::combine(const String& item1, const String& item2, const String& item3)
|
||||
{ return combine(combine(item1, item2), item3); }
|
||||
|
||||
cv::String cv::Path::change_extension(const String& file, const String& ext)
|
||||
{
|
||||
String::size_type pos = file.find_last_of('.');
|
||||
return pos == String::npos ? file : file.substr(0, pos+1) + ext;
|
||||
}
|
|
@ -0,0 +1,87 @@
|
|||
/*M///////////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
|
||||
//
|
||||
// By downloading, copying, installing or using the software you agree to this license.
|
||||
// If you do not agree to this license, do not download, install,
|
||||
// copy or use the software.
|
||||
//
|
||||
//
|
||||
// License Agreement
|
||||
// For Open Source Computer Vision Library
|
||||
//
|
||||
// Copyright (C) 2013, OpenCV Foundation, all rights reserved.
|
||||
// Third party copyrights are property of their respective owners.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without modification,
|
||||
// are permitted provided that the following conditions are met:
|
||||
//
|
||||
// * Redistribution's of source code must retain the above copyright notice,
|
||||
// this list of conditions and the following disclaimer.
|
||||
//
|
||||
// * Redistribution's in binary form must reproduce the above copyright notice,
|
||||
// this list of conditions and the following disclaimer in the documentation
|
||||
// and/or other materials provided with the distribution.
|
||||
//
|
||||
// * The name of the copyright holders may not be used to endorse or promote products
|
||||
// derived from this software without specific prior written permission.
|
||||
//
|
||||
// This software is provided by the copyright holders and contributors "as is" and
|
||||
// any express or implied warranties, including, but not limited to, the implied
|
||||
// warranties of merchantability and fitness for a particular purpose are disclaimed.
|
||||
// In no event shall the Intel Corporation or contributors be liable for any direct,
|
||||
// indirect, incidental, special, exemplary, or consequential damages
|
||||
// (including, but not limited to, procurement of substitute goods or services;
|
||||
// loss of use, data, or profits; or business interruption) however caused
|
||||
// and on any theory of liability, whether in contract, strict liability,
|
||||
// or tort (including negligence or otherwise) arising in any way out of
|
||||
// the use of this software, even if advised of the possibility of such damage.
|
||||
//
|
||||
// Authors:
|
||||
// * Ozan Tonkal, ozantonkal@gmail.com
|
||||
// * Anatoly Baksheev, Itseez Inc. myname.mysurname <> mycompany.com
|
||||
//
|
||||
//M*/
|
||||
|
||||
#ifndef OPENCV_VIZ_TEST_COMMON_HPP
|
||||
#define OPENCV_VIZ_TEST_COMMON_HPP
|
||||
|
||||
#include <opencv2/viz/vizcore.hpp>
|
||||
|
||||
namespace cv
|
||||
{
|
||||
struct Path
|
||||
{
|
||||
static String combine(const String& item1, const String& item2);
|
||||
static String combine(const String& item1, const String& item2, const String& item3);
|
||||
static String change_extension(const String& file, const String& ext);
|
||||
};
|
||||
|
||||
inline cv::String get_dragon_ply_file_path()
|
||||
{
|
||||
return Path::combine(cvtest::TS::ptr()->get_data_path(), "dragon.ply");
|
||||
}
|
||||
|
||||
template<typename _Tp>
|
||||
inline std::vector< Affine3<_Tp> > generate_test_trajectory()
|
||||
{
|
||||
std::vector< Affine3<_Tp> > result;
|
||||
|
||||
for (int i = 0, j = 0; i <= 270; i += 3, j += 10)
|
||||
{
|
||||
double x = 2 * cos(i * 3 * CV_PI/180.0) * (1.0 + 0.5 * cos(1.2 + i * 1.2 * CV_PI/180.0));
|
||||
double y = 0.25 + i/270.0 + sin(j * CV_PI/180.0) * 0.2 * sin(0.6 + j * 1.5 * CV_PI/180.0);
|
||||
double z = 2 * sin(i * 3 * CV_PI/180.0) * (1.0 + 0.5 * cos(1.2 + i * CV_PI/180.0));
|
||||
result.push_back(viz::makeCameraPose(Vec3d(x, y, z), Vec3d::all(0.0), Vec3d(0.0, 1.0, 0.0)));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
inline Mat make_gray(const Mat& image)
|
||||
{
|
||||
Mat chs[3]; split(image, chs);
|
||||
return 0.114 * chs[0] + 0.58 * chs[1] + 0.3 * chs[2];
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
|
@ -0,0 +1,6 @@
|
|||
// This file is part of OpenCV project.
|
||||
// It is subject to the license terms in the LICENSE file found in the top-level directory
|
||||
// of this distribution and at http://opencv.org/license.html.
|
||||
#include "test_precomp.hpp"
|
||||
|
||||
CV_TEST_MAIN("viz")
|
|
@ -0,0 +1,10 @@
|
|||
// This file is part of OpenCV project.
|
||||
// It is subject to the license terms in the LICENSE file found in the top-level directory
|
||||
// of this distribution and at http://opencv.org/license.html.
|
||||
#include "opencv2/ts.hpp"
|
||||
#include "test_common.hpp"
|
||||
|
||||
namespace opencv_test
|
||||
{
|
||||
using namespace cv::viz;
|
||||
}
|
|
@ -0,0 +1,58 @@
|
|||
// This file is part of OpenCV project.
|
||||
// It is subject to the license terms in the LICENSE file found in the top-level directory
|
||||
// of this distribution and at http://opencv.org/license.html.
|
||||
#include "test_precomp.hpp"
|
||||
|
||||
namespace opencv_test { namespace {
|
||||
|
||||
static void tutorial2()
|
||||
{
|
||||
/// Create a window
|
||||
viz::Viz3d myWindow("Coordinate Frame");
|
||||
|
||||
/// Add coordinate axes
|
||||
myWindow.showWidget("Coordinate Widget", viz::WCoordinateSystem());
|
||||
|
||||
/// Add line to represent (1,1,1) axis
|
||||
viz::WLine axis(Point3f(-1.0, -1.0, -1.0), Point3d(1.0, 1.0, 1.0));
|
||||
axis.setRenderingProperty(viz::LINE_WIDTH, 4.0);
|
||||
myWindow.showWidget("Line Widget", axis);
|
||||
|
||||
/// Construct a cube widget
|
||||
viz::WCube cube_widget(Point3d(0.5, 0.5, 0.0), Point3d(0.0, 0.0, -0.5), true, viz::Color::blue());
|
||||
cube_widget.setRenderingProperty(viz::LINE_WIDTH, 4.0);
|
||||
|
||||
/// Display widget (update if already displayed)
|
||||
myWindow.showWidget("Cube Widget", cube_widget);
|
||||
|
||||
/// Rodrigues vector
|
||||
Vec3d rot_vec = Vec3d::all(0);
|
||||
double translation_phase = 0.0, translation = 0.0;
|
||||
for(unsigned num = 0; num < 50; ++num)
|
||||
{
|
||||
/* Rotation using rodrigues */
|
||||
/// Rotate around (1,1,1)
|
||||
rot_vec[0] += CV_PI * 0.01;
|
||||
rot_vec[1] += CV_PI * 0.01;
|
||||
rot_vec[2] += CV_PI * 0.01;
|
||||
|
||||
/// Shift on (1,1,1)
|
||||
translation_phase += CV_PI * 0.01;
|
||||
translation = sin(translation_phase);
|
||||
|
||||
/// Construct pose
|
||||
Affine3d pose(rot_vec, Vec3d(translation, translation, translation));
|
||||
|
||||
myWindow.setWidgetPose("Cube Widget", pose);
|
||||
|
||||
myWindow.spinOnce(100, true);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
TEST(Viz, DISABLED_tutorial2_pose_of_widget)
|
||||
{
|
||||
tutorial2();
|
||||
}
|
||||
|
||||
}} // namespace
|
|
@ -0,0 +1,64 @@
|
|||
// This file is part of OpenCV project.
|
||||
// It is subject to the license terms in the LICENSE file found in the top-level directory
|
||||
// of this distribution and at http://opencv.org/license.html.
|
||||
#include "test_precomp.hpp"
|
||||
|
||||
namespace opencv_test { namespace {
|
||||
|
||||
/**
|
||||
* @function main
|
||||
*/
|
||||
static void tutorial3(bool camera_pov)
|
||||
{
|
||||
/// Create a window
|
||||
viz::Viz3d myWindow("Coordinate Frame");
|
||||
|
||||
/// Add coordinate axes
|
||||
myWindow.showWidget("Coordinate Widget", viz::WCoordinateSystem());
|
||||
|
||||
/// Let's assume camera has the following properties
|
||||
Point3d cam_origin(3.0, 3.0, 3.0), cam_focal_point(3.0, 3.0, 2.0), cam_y_dir(-1.0, 0.0, 0.0);
|
||||
|
||||
/// We can get the pose of the cam using makeCameraPose
|
||||
Affine3d camera_pose = viz::makeCameraPose(cam_origin, cam_focal_point, cam_y_dir);
|
||||
|
||||
/// We can get the transformation matrix from camera coordinate system to global using
|
||||
/// - makeTransformToGlobal. We need the axes of the camera
|
||||
Affine3d transform = viz::makeTransformToGlobal(Vec3d(0.0, -1.0, 0.0), Vec3d(-1.0, 0.0, 0.0), Vec3d(0.0, 0.0, -1.0), cam_origin);
|
||||
|
||||
/// Create a cloud widget.
|
||||
Mat dragon_cloud = viz::readCloud(get_dragon_ply_file_path());
|
||||
viz::WCloud cloud_widget(dragon_cloud, viz::Color::green());
|
||||
|
||||
/// Pose of the widget in camera frame
|
||||
Affine3d cloud_pose = Affine3d().rotate(Vec3d(0.0, CV_PI/2, 0.0)).rotate(Vec3d(0.0, 0.0, CV_PI)).translate(Vec3d(0.0, 0.0, 3.0));
|
||||
/// Pose of the widget in global frame
|
||||
Affine3d cloud_pose_global = transform * cloud_pose;
|
||||
|
||||
/// Visualize camera frame
|
||||
myWindow.showWidget("CPW_FRUSTUM", viz::WCameraPosition(Vec2f(0.889484f, 0.523599f)), camera_pose);
|
||||
if (!camera_pov)
|
||||
myWindow.showWidget("CPW", viz::WCameraPosition(0.5), camera_pose);
|
||||
|
||||
/// Visualize widget
|
||||
myWindow.showWidget("bunny", cloud_widget, cloud_pose_global);
|
||||
|
||||
/// Set the viewer pose to that of camera
|
||||
if (camera_pov)
|
||||
myWindow.setViewerPose(camera_pose);
|
||||
|
||||
/// Start event loop.
|
||||
myWindow.spinOnce(500, true);
|
||||
}
|
||||
|
||||
TEST(Viz, tutorial3_global_view)
|
||||
{
|
||||
tutorial3(false);
|
||||
}
|
||||
|
||||
TEST(Viz, tutorial3_camera_view)
|
||||
{
|
||||
tutorial3(true);
|
||||
}
|
||||
|
||||
}} // namespace
|
|
@ -0,0 +1,65 @@
|
|||
/*M///////////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
|
||||
//
|
||||
// By downloading, copying, installing or using the software you agree to this license.
|
||||
// If you do not agree to this license, do not download, install,
|
||||
// copy or use the software.
|
||||
//
|
||||
//
|
||||
// License Agreement
|
||||
// For Open Source Computer Vision Library
|
||||
//
|
||||
// Copyright (C) 2000-2008, Intel Corporation, all rights reserved.
|
||||
// Copyright (C) 2008-2013, Willow Garage Inc., all rights reserved.
|
||||
// Third party copyrights are property of their respective owners.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without modification,
|
||||
// are permitted provided that the following conditions are met:
|
||||
//
|
||||
// * Redistribution's of source code must retain the above copyright notice,
|
||||
// this list of conditions and the following disclaimer.
|
||||
//
|
||||
// * Redistribution's in binary form must reproduce the above copyright notice,
|
||||
// this list of conditions and the following disclaimer in the documentation
|
||||
// and / or other materials provided with the distribution.
|
||||
//
|
||||
// * The name of the copyright holders may not be used to endorse or promote products
|
||||
// derived from this software without specific prior written permission.
|
||||
//
|
||||
// This software is provided by the copyright holders and contributors "as is" and
|
||||
// any express or implied warranties, including, but not limited to, the implied
|
||||
// warranties of merchantability and fitness for a particular purpose are disclaimed.
|
||||
// In no event shall the Intel Corporation or contributors be liable for any direct,
|
||||
// indirect, incidental, special, exemplary, or consequential damages
|
||||
// (including, but not limited to, procurement of substitute goods or services;
|
||||
// loss of use, data, or profits; or business interruption) however caused
|
||||
// and on any theory of liability, whether in contract, strict liability,
|
||||
// or tort (including negligence or otherwise) arising in any way out of
|
||||
// the use of this software, even if advised of the possibility of such damage.
|
||||
//
|
||||
//M*/
|
||||
#include "test_precomp.hpp"
|
||||
|
||||
namespace opencv_test { namespace {
|
||||
|
||||
TEST(Viz_viz3d, DISABLED_develop)
|
||||
{
|
||||
cv::Mat cloud = cv::viz::readCloud(get_dragon_ply_file_path());
|
||||
|
||||
cv::viz::Viz3d viz("abc");
|
||||
viz.setBackgroundMeshLab();
|
||||
viz.showWidget("coo", cv::viz::WCoordinateSystem(1));
|
||||
viz.showWidget("cloud", cv::viz::WPaintedCloud(cloud));
|
||||
|
||||
//---->>>>> <to_test_in_future>
|
||||
//std::vector<cv::Affine3d> gt, es;
|
||||
//cv::viz::readTrajectory(gt, "d:/Datasets/trajs/gt%05d.xml");
|
||||
//cv::viz::readTrajectory(es, "d:/Datasets/trajs/es%05d.xml");
|
||||
//cv::Mat cloud = cv::viz::readCloud(get_dragon_ply_file_path());
|
||||
//---->>>>> </to_test_in_future>
|
||||
|
||||
viz.spinOnce(500, true);
|
||||
}
|
||||
|
||||
}} // namespace
|
|
@ -0,0 +1,454 @@
|
|||
/*M///////////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
|
||||
//
|
||||
// By downloading, copying, installing or using the software you agree to this license.
|
||||
// If you do not agree to this license, do not download, install,
|
||||
// copy or use the software.
|
||||
//
|
||||
//
|
||||
// License Agreement
|
||||
// For Open Source Computer Vision Library
|
||||
//
|
||||
// Copyright (C) 2000-2008, Intel Corporation, all rights reserved.
|
||||
// Copyright (C) 2008-2013, Willow Garage Inc., all rights reserved.
|
||||
// Third party copyrights are property of their respective owners.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without modification,
|
||||
// are permitted provided that the following conditions are met:
|
||||
//
|
||||
// * Redistribution's of source code must retain the above copyright notice,
|
||||
// this list of conditions and the following disclaimer.
|
||||
//
|
||||
// * Redistribution's in binary form must reproduce the above copyright notice,
|
||||
// this list of conditions and the following disclaimer in the documentation
|
||||
// and / or other materials provided with the distribution.
|
||||
//
|
||||
// * The name of the copyright holders may not be used to endorse or promote products
|
||||
// derived from this software without specific prior written permission.
|
||||
//
|
||||
// This software is provided by the copyright holders and contributors "as is" and
|
||||
// any express or implied warranties, including, but not limited to, the implied
|
||||
// warranties of merchantability and fitness for a particular purpose are disclaimed.
|
||||
// In no event shall the Intel Corporation or contributors be liable for any direct,
|
||||
// indirect, incidental, special, exemplary, or consequential damages
|
||||
// (including, but not limited to, procurement of substitute goods or services;
|
||||
// loss of use, data, or profits; or business interruption) however caused
|
||||
// and on any theory of liability, whether in contract, strict liability,
|
||||
// or tort (including negligence or otherwise) arising in any way out of
|
||||
// the use of this software, even if advised of the possibility of such damage.
|
||||
//
|
||||
//M*/
|
||||
|
||||
#include "test_precomp.hpp"
|
||||
|
||||
namespace opencv_test { namespace {
|
||||
|
||||
TEST(Viz, show_cloud_bluberry)
|
||||
{
|
||||
Mat dragon_cloud = readCloud(get_dragon_ply_file_path());
|
||||
|
||||
Affine3d pose = Affine3d().rotate(Vec3d(0, 0.8, 0));
|
||||
|
||||
Viz3d viz("show_cloud_bluberry");
|
||||
viz.setBackgroundColor(Color::black());
|
||||
viz.showWidget("coosys", WCoordinateSystem());
|
||||
viz.showWidget("dragon", WCloud(dragon_cloud, Color::bluberry()), pose);
|
||||
|
||||
viz.showWidget("text2d", WText("Bluberry cloud", Point(20, 20), 20, Color::green()));
|
||||
viz.spinOnce(500, true);
|
||||
}
|
||||
|
||||
TEST(Viz, show_cloud_random_color)
|
||||
{
|
||||
Mat dragon_cloud = readCloud(get_dragon_ply_file_path());
|
||||
|
||||
Mat colors(dragon_cloud.size(), CV_8UC3);
|
||||
theRNG().fill(colors, RNG::UNIFORM, 0, 255);
|
||||
|
||||
Affine3d pose = Affine3d().rotate(Vec3d(0, 0.8, 0));
|
||||
|
||||
Viz3d viz("show_cloud_random_color");
|
||||
viz.setBackgroundMeshLab();
|
||||
viz.showWidget("coosys", WCoordinateSystem());
|
||||
viz.showWidget("dragon", WCloud(dragon_cloud, colors), pose);
|
||||
viz.showWidget("text2d", WText("Random color cloud", Point(20, 20), 20, Color::green()));
|
||||
viz.spinOnce(500, true);
|
||||
}
|
||||
|
||||
TEST(Viz, show_cloud_masked)
|
||||
{
|
||||
Mat dragon_cloud = readCloud(get_dragon_ply_file_path());
|
||||
|
||||
Vec3f qnan = Vec3f::all(std::numeric_limits<float>::quiet_NaN());
|
||||
for(int i = 0; i < (int)dragon_cloud.total(); ++i)
|
||||
if (i % 15 != 0)
|
||||
dragon_cloud.at<Vec3f>(i) = qnan;
|
||||
|
||||
Affine3d pose = Affine3d().rotate(Vec3d(0, 0.8, 0));
|
||||
|
||||
Viz3d viz("show_cloud_masked");
|
||||
viz.showWidget("coosys", WCoordinateSystem());
|
||||
viz.showWidget("dragon", WCloud(dragon_cloud), pose);
|
||||
viz.showWidget("text2d", WText("Nan masked cloud", Point(20, 20), 20, Color::green()));
|
||||
viz.spinOnce(500, true);
|
||||
}
|
||||
|
||||
TEST(Viz, show_cloud_collection)
|
||||
{
|
||||
Mat cloud = readCloud(get_dragon_ply_file_path());
|
||||
|
||||
WCloudCollection ccol;
|
||||
ccol.addCloud(cloud, Color::white(), Affine3d().translate(Vec3d(0, 0, 0)).rotate(Vec3d(CV_PI/2, 0, 0)));
|
||||
ccol.addCloud(cloud, Color::blue(), Affine3d().translate(Vec3d(1, 0, 0)));
|
||||
ccol.addCloud(cloud, Color::red(), Affine3d().translate(Vec3d(2, 0, 0)));
|
||||
ccol.finalize();
|
||||
|
||||
Viz3d viz("show_cloud_collection");
|
||||
viz.setBackgroundColor(Color::mlab());
|
||||
viz.showWidget("coosys", WCoordinateSystem());
|
||||
viz.showWidget("ccol", ccol);
|
||||
viz.showWidget("text2d", WText("Cloud collection", Point(20, 20), 20, Color::green()));
|
||||
viz.spinOnce(500, true);
|
||||
}
|
||||
|
||||
TEST(Viz, show_painted_clouds)
|
||||
{
|
||||
Mat cloud = readCloud(get_dragon_ply_file_path());
|
||||
|
||||
Viz3d viz("show_painted_clouds");
|
||||
viz.setBackgroundMeshLab();
|
||||
viz.showWidget("coosys", WCoordinateSystem());
|
||||
viz.showWidget("cloud1", WPaintedCloud(cloud), Affine3d(Vec3d(0.0, -CV_PI/2, 0.0), Vec3d(-1.5, 0.0, 0.0)));
|
||||
viz.showWidget("cloud2", WPaintedCloud(cloud, Vec3d(0.0, -0.75, -1.0), Vec3d(0.0, 0.75, 0.0)), Affine3d(Vec3d(0.0, CV_PI/2, 0.0), Vec3d(1.5, 0.0, 0.0)));
|
||||
viz.showWidget("cloud3", WPaintedCloud(cloud, Vec3d(0.0, 0.0, -1.0), Vec3d(0.0, 0.0, 1.0), Color::blue(), Color::red()));
|
||||
viz.showWidget("arrow", WArrow(Vec3d(0.0, 1.0, -1.0), Vec3d(0.0, 1.0, 1.0), 0.009, Color::raspberry()));
|
||||
viz.showWidget("text2d", WText("Painted clouds", Point(20, 20), 20, Color::green()));
|
||||
viz.spinOnce(500, true);
|
||||
}
|
||||
|
||||
TEST(Viz, show_mesh)
|
||||
{
|
||||
Mesh mesh = Mesh::load(get_dragon_ply_file_path());
|
||||
|
||||
Affine3d pose = Affine3d().rotate(Vec3d(0, 0.8, 0));
|
||||
|
||||
Viz3d viz("show_mesh");
|
||||
viz.showWidget("coosys", WCoordinateSystem());
|
||||
viz.showWidget("mesh", WMesh(mesh), pose);
|
||||
viz.showWidget("text2d", WText("Just mesh", Point(20, 20), 20, Color::green()));
|
||||
viz.spinOnce(500, true);
|
||||
}
|
||||
|
||||
TEST(Viz, show_mesh_random_colors)
|
||||
{
|
||||
Mesh mesh = Mesh::load(get_dragon_ply_file_path());
|
||||
theRNG().fill(mesh.colors, RNG::UNIFORM, 0, 255);
|
||||
|
||||
Affine3d pose = Affine3d().rotate(Vec3d(0, 0.8, 0));
|
||||
|
||||
Viz3d viz("show_mesh_random_color");
|
||||
viz.showWidget("coosys", WCoordinateSystem());
|
||||
viz.showWidget("mesh", WMesh(mesh), pose);
|
||||
viz.setRenderingProperty("mesh", SHADING, SHADING_PHONG);
|
||||
viz.showWidget("text2d", WText("Random color mesh", Point(20, 20), 20, Color::green()));
|
||||
viz.spinOnce(500, true);
|
||||
}
|
||||
|
||||
TEST(Viz, show_widget_merger)
|
||||
{
|
||||
WWidgetMerger merger;
|
||||
merger.addWidget(WCube(Vec3d::all(0.0), Vec3d::all(1.0), true, Color::gold()));
|
||||
|
||||
RNG& rng = theRNG();
|
||||
for(int i = 0; i < 77; ++i)
|
||||
{
|
||||
Vec3b c;
|
||||
rng.fill(c, RNG::NORMAL, Scalar::all(128), Scalar::all(48), true);
|
||||
merger.addWidget(WSphere(Vec3d(c)*(1.0/255.0), 7.0/255.0, 10, Color(c[2], c[1], c[0])));
|
||||
}
|
||||
merger.finalize();
|
||||
|
||||
Viz3d viz("show_mesh_random_color");
|
||||
viz.showWidget("coo", WCoordinateSystem());
|
||||
viz.showWidget("merger", merger);
|
||||
viz.showWidget("text2d", WText("Widget merger", Point(20, 20), 20, Color::green()));
|
||||
viz.spinOnce(500, true);
|
||||
}
|
||||
|
||||
TEST(Viz, show_textured_mesh)
|
||||
{
|
||||
Mat lena = imread(Path::combine(cvtest::TS::ptr()->get_data_path(), "lena.png"));
|
||||
|
||||
std::vector<Vec3d> points;
|
||||
std::vector<Vec2d> tcoords;
|
||||
std::vector<int> polygons;
|
||||
for(size_t i = 0; i < 64; ++i)
|
||||
{
|
||||
double angle = CV_PI/2 * i/64.0;
|
||||
points.push_back(Vec3d(0.00, cos(angle), sin(angle))*0.75);
|
||||
points.push_back(Vec3d(1.57, cos(angle), sin(angle))*0.75);
|
||||
tcoords.push_back(Vec2d(0.0, i/64.0));
|
||||
tcoords.push_back(Vec2d(1.0, i/64.0));
|
||||
}
|
||||
|
||||
for(int i = 0; i < (int)points.size()/2-1; ++i)
|
||||
{
|
||||
int polys[] = {3, 2*i, 2*i+1, 2*i+2, 3, 2*i+1, 2*i+2, 2*i+3};
|
||||
polygons.insert(polygons.end(), polys, polys + sizeof(polys)/sizeof(polys[0]));
|
||||
}
|
||||
|
||||
cv::viz::Mesh mesh;
|
||||
mesh.cloud = Mat(points, true).reshape(3, 1);
|
||||
mesh.tcoords = Mat(tcoords, true).reshape(2, 1);
|
||||
mesh.polygons = Mat(polygons, true).reshape(1, 1);
|
||||
mesh.texture = lena;
|
||||
|
||||
Viz3d viz("show_textured_mesh");
|
||||
viz.setBackgroundMeshLab();
|
||||
viz.showWidget("coosys", WCoordinateSystem());
|
||||
viz.showWidget("mesh", WMesh(mesh));
|
||||
viz.setRenderingProperty("mesh", SHADING, SHADING_PHONG);
|
||||
viz.showWidget("text2d", WText("Textured mesh", Point(20, 20), 20, Color::green()));
|
||||
viz.spinOnce(500, true);
|
||||
}
|
||||
|
||||
TEST(Viz, show_polyline)
|
||||
{
|
||||
const Color palette[] = { Color::red(), Color::green(), Color::blue(), Color::gold(), Color::raspberry(), Color::bluberry(), Color::lime() };
|
||||
size_t palette_size = sizeof(palette)/sizeof(palette[0]);
|
||||
|
||||
Mat polyline(1, 32, CV_64FC3), colors(1, 32, CV_8UC3);
|
||||
for(int i = 0; i < (int)polyline.total(); ++i)
|
||||
{
|
||||
polyline.at<Vec3d>(i) = Vec3d(i/16.0, cos(i * CV_PI/6), sin(i * CV_PI/6));
|
||||
colors.at<Vec3b>(i) = palette[i & palette_size];
|
||||
}
|
||||
|
||||
Viz3d viz("show_polyline");
|
||||
viz.showWidget("polyline", WPolyLine(polyline, colors));
|
||||
viz.showWidget("coosys", WCoordinateSystem());
|
||||
viz.showWidget("text2d", WText("Polyline", Point(20, 20), 20, Color::green()));
|
||||
viz.spinOnce(500, true);
|
||||
}
|
||||
|
||||
TEST(Viz, show_sampled_normals)
|
||||
{
|
||||
Mesh mesh = Mesh::load(get_dragon_ply_file_path());
|
||||
computeNormals(mesh, mesh.normals);
|
||||
|
||||
Affine3d pose = Affine3d().rotate(Vec3d(0, 0.8, 0));
|
||||
|
||||
Viz3d viz("show_sampled_normals");
|
||||
viz.showWidget("mesh", WMesh(mesh), pose);
|
||||
viz.showWidget("normals", WCloudNormals(mesh.cloud, mesh.normals, 30, 0.1f, Color::green()), pose);
|
||||
viz.setRenderingProperty("normals", LINE_WIDTH, 2.0);
|
||||
viz.showWidget("text2d", WText("Cloud or mesh normals", Point(20, 20), 20, Color::green()));
|
||||
viz.spinOnce(500, true);
|
||||
}
|
||||
|
||||
TEST(Viz, show_cloud_shaded_by_normals)
|
||||
{
|
||||
Mesh mesh = Mesh::load(get_dragon_ply_file_path());
|
||||
computeNormals(mesh, mesh.normals);
|
||||
|
||||
Affine3d pose = Affine3d().rotate(Vec3d(0, 0.8, 0));
|
||||
|
||||
WCloud cloud(mesh.cloud, Color::white(), mesh.normals);
|
||||
cloud.setRenderingProperty(SHADING, SHADING_GOURAUD);
|
||||
|
||||
Viz3d viz("show_cloud_shaded_by_normals");
|
||||
viz.showWidget("cloud", cloud, pose);
|
||||
viz.showWidget("text2d", WText("Cloud shaded by normals", Point(20, 20), 20, Color::green()));
|
||||
viz.spinOnce(500, true);
|
||||
}
|
||||
|
||||
TEST(Viz, show_trajectories)
|
||||
{
|
||||
std::vector<Affine3d> path = generate_test_trajectory<double>(), sub0, sub1, sub2, sub3, sub4, sub5;
|
||||
int size =(int)path.size();
|
||||
|
||||
Mat(path).rowRange(0, size/10+1).copyTo(sub0);
|
||||
Mat(path).rowRange(size/10, size/5+1).copyTo(sub1);
|
||||
Mat(path).rowRange(size/5, 11*size/12).copyTo(sub2);
|
||||
Mat(path).rowRange(11*size/12, size).copyTo(sub3);
|
||||
Mat(path).rowRange(3*size/4, 33*size/40).copyTo(sub4);
|
||||
Mat(path).rowRange(33*size/40, 9*size/10).copyTo(sub5);
|
||||
Matx33d K(1024.0, 0.0, 320.0, 0.0, 1024.0, 240.0, 0.0, 0.0, 1.0);
|
||||
|
||||
Viz3d viz("show_trajectories");
|
||||
viz.showWidget("coos", WCoordinateSystem());
|
||||
viz.showWidget("sub0", WTrajectorySpheres(sub0, 0.25, 0.07));
|
||||
viz.showWidget("sub1", WTrajectory(sub1, WTrajectory::PATH, 0.2, Color::brown()));
|
||||
viz.showWidget("sub2", WTrajectory(sub2, WTrajectory::FRAMES, 0.2));
|
||||
viz.showWidget("sub3", WTrajectory(sub3, WTrajectory::BOTH, 0.2, Color::green()));
|
||||
viz.showWidget("sub4", WTrajectoryFrustums(sub4, K, 0.3, Color::yellow()));
|
||||
viz.showWidget("sub5", WTrajectoryFrustums(sub5, Vec2d(0.78, 0.78), 0.15));
|
||||
viz.showWidget("text2d", WText("Different kinds of supported trajectories", Point(20, 20), 20, Color::green()));
|
||||
|
||||
int i = 0;
|
||||
for(unsigned num = 0; num < 50; ++num)
|
||||
{
|
||||
double a = --i % 360;
|
||||
Vec3d pose(sin(a * CV_PI/180), 0.7, cos(a * CV_PI/180));
|
||||
viz.setViewerPose(makeCameraPose(pose * 7.5, Vec3d(0.0, 0.5, 0.0), Vec3d(0.0, 0.1, 0.0)));
|
||||
viz.spinOnce(100, true);
|
||||
}
|
||||
viz.resetCamera();
|
||||
viz.spinOnce(500, true);
|
||||
}
|
||||
|
||||
TEST(Viz, show_trajectory_reposition)
|
||||
{
|
||||
std::vector<Affine3f> path = generate_test_trajectory<float>();
|
||||
|
||||
Viz3d viz("show_trajectory_reposition_to_origin");
|
||||
viz.showWidget("coos", WCoordinateSystem());
|
||||
viz.showWidget("sub3", WTrajectory(Mat(path).rowRange(0, (int)path.size()/3), WTrajectory::BOTH, 0.2, Color::brown()), path.front().inv());
|
||||
viz.showWidget("text2d", WText("Trajectory resposition to origin", Point(20, 20), 20, Color::green()));
|
||||
viz.spinOnce(500, true);
|
||||
}
|
||||
|
||||
TEST(Viz, show_camera_positions)
|
||||
{
|
||||
Matx33d K(1024.0, 0.0, 320.0, 0.0, 1024.0, 240.0, 0.0, 0.0, 1.0);
|
||||
Mat lena = imread(Path::combine(cvtest::TS::ptr()->get_data_path(), "lena.png"));
|
||||
Mat gray = make_gray(lena);
|
||||
|
||||
Affine3d poses[2];
|
||||
for(int i = 0; i < 2; ++i)
|
||||
{
|
||||
Vec3d pose = 5 * Vec3d(sin(3.14 + 2.7 + i*60 * CV_PI/180), 0.4 - i*0.3, cos(3.14 + 2.7 + i*60 * CV_PI/180));
|
||||
poses[i] = makeCameraPose(pose, Vec3d(0.0, 0.0, 0.0), Vec3d(0.0, -0.1, 0.0));
|
||||
}
|
||||
|
||||
Viz3d viz("show_camera_positions");
|
||||
viz.showWidget("sphe", WSphere(Point3d(0,0,0), 1.0, 10, Color::orange_red()));
|
||||
viz.showWidget("coos", WCoordinateSystem(1.5));
|
||||
viz.showWidget("pos1", WCameraPosition(0.75), poses[0]);
|
||||
viz.showWidget("pos2", WCameraPosition(Vec2d(0.78, 0.78), lena, 2.2, Color::green()), poses[0]);
|
||||
viz.showWidget("pos3", WCameraPosition(0.75), poses[1]);
|
||||
viz.showWidget("pos4", WCameraPosition(K, gray, 3, Color::indigo()), poses[1]);
|
||||
viz.showWidget("text2d", WText("Camera positions with images", Point(20, 20), 20, Color::green()));
|
||||
viz.spinOnce(500, true);
|
||||
}
|
||||
|
||||
TEST(Viz, show_overlay_image)
|
||||
{
|
||||
Mat lena = imread(Path::combine(cvtest::TS::ptr()->get_data_path(), "lena.png"));
|
||||
Mat gray = make_gray(lena);
|
||||
|
||||
Size2d half_lsize = Size2d(lena.size()) * 0.5;
|
||||
|
||||
Viz3d viz("show_overlay_image");
|
||||
viz.setBackgroundMeshLab();
|
||||
Size vsz = viz.getWindowSize();
|
||||
|
||||
viz.showWidget("coos", WCoordinateSystem());
|
||||
viz.showWidget("cube", WCube());
|
||||
viz.showWidget("img1", WImageOverlay(lena, Rect(Point(10, 10), half_lsize)));
|
||||
viz.showWidget("img2", WImageOverlay(gray, Rect(Point(vsz.width-10-lena.cols/2, 10), half_lsize)));
|
||||
viz.showWidget("img3", WImageOverlay(gray, Rect(Point(10, vsz.height-10-lena.rows/2), half_lsize)));
|
||||
viz.showWidget("img5", WImageOverlay(lena, Rect(Point(vsz.width-10-lena.cols/2, vsz.height-10-lena.rows/2), half_lsize)));
|
||||
viz.showWidget("text2d", WText("Overlay images", Point(20, 20), 20, Color::green()));
|
||||
|
||||
int i = 0;
|
||||
for(unsigned num = 0; num < 50; ++num)
|
||||
{
|
||||
double a = ++i % 360;
|
||||
Vec3d pose(sin(a * CV_PI/180), 0.7, cos(a * CV_PI/180));
|
||||
viz.setViewerPose(makeCameraPose(pose * 3, Vec3d(0.0, 0.5, 0.0), Vec3d(0.0, 0.1, 0.0)));
|
||||
viz.getWidget("img1").cast<WImageOverlay>().setImage(lena * pow(sin(i*10*CV_PI/180) * 0.5 + 0.5, 1.0));
|
||||
viz.spinOnce(100, true);
|
||||
}
|
||||
viz.showWidget("text2d", WText("Overlay images (stopped)", Point(20, 20), 20, Color::green()));
|
||||
viz.spinOnce(500, true);
|
||||
}
|
||||
|
||||
|
||||
TEST(Viz, show_image_method)
|
||||
{
|
||||
Mat lena = imread(Path::combine(cvtest::TS::ptr()->get_data_path(), "lena.png"));
|
||||
|
||||
Viz3d viz("show_image_method");
|
||||
viz.showImage(lena);
|
||||
viz.spinOnce(1500, true);
|
||||
viz.showImage(lena, lena.size());
|
||||
viz.spinOnce(1500, true);
|
||||
|
||||
cv::viz::imshow("show_image_method", make_gray(lena)).spinOnce(500, true);
|
||||
}
|
||||
|
||||
TEST(Viz, show_image_3d)
|
||||
{
|
||||
Mat lena = imread(Path::combine(cvtest::TS::ptr()->get_data_path(), "lena.png"));
|
||||
Mat gray = make_gray(lena);
|
||||
|
||||
Viz3d viz("show_image_3d");
|
||||
viz.setBackgroundMeshLab();
|
||||
viz.showWidget("coos", WCoordinateSystem());
|
||||
viz.showWidget("cube", WCube());
|
||||
viz.showWidget("arr0", WArrow(Vec3d(0.5, 0.0, 0.0), Vec3d(1.5, 0.0, 0.0), 0.009, Color::raspberry()));
|
||||
viz.showWidget("img0", WImage3D(lena, Size2d(1.0, 1.0)), Affine3d(Vec3d(0.0, CV_PI/2, 0.0), Vec3d(.5, 0.0, 0.0)));
|
||||
viz.showWidget("arr1", WArrow(Vec3d(-0.5, -0.5, 0.0), Vec3d(0.2, 0.2, 0.0), 0.009, Color::raspberry()));
|
||||
viz.showWidget("img1", WImage3D(gray, Size2d(1.0, 1.0), Vec3d(-0.5, -0.5, 0.0), Vec3d(1.0, 1.0, 0.0), Vec3d(0.0, 1.0, 0.0)));
|
||||
|
||||
viz.showWidget("arr3", WArrow(Vec3d::all(-0.5), Vec3d::all(0.5), 0.009, Color::raspberry()));
|
||||
|
||||
viz.showWidget("text2d", WText("Images in 3D", Point(20, 20), 20, Color::green()));
|
||||
|
||||
int i = 0;
|
||||
for(unsigned num = 0; num < 50; ++num)
|
||||
{
|
||||
viz.getWidget("img0").cast<WImage3D>().setImage(lena * pow(sin(i++*7.5*CV_PI/180) * 0.5 + 0.5, 1.0));
|
||||
viz.spinOnce(100, true);
|
||||
}
|
||||
viz.showWidget("text2d", WText("Images in 3D (stopped)", Point(20, 20), 20, Color::green()));
|
||||
viz.spinOnce(500, true);
|
||||
}
|
||||
|
||||
TEST(Viz, show_simple_widgets)
|
||||
{
|
||||
Viz3d viz("show_simple_widgets");
|
||||
viz.setBackgroundMeshLab();
|
||||
|
||||
viz.showWidget("coos", WCoordinateSystem());
|
||||
viz.showWidget("cube", WCube());
|
||||
viz.showWidget("cub0", WCube(Vec3d::all(-1.0), Vec3d::all(-0.5), false, Color::indigo()));
|
||||
viz.showWidget("arro", WArrow(Vec3d::all(-0.5), Vec3d::all(0.5), 0.009, Color::raspberry()));
|
||||
viz.showWidget("cir1", WCircle(0.5, 0.01, Color::bluberry()));
|
||||
viz.showWidget("cir2", WCircle(0.5, Point3d(0.5, 0.0, 0.0), Vec3d(1.0, 0.0, 0.0), 0.01, Color::apricot()));
|
||||
|
||||
viz.showWidget("cyl0", WCylinder(Vec3d(-0.5, 0.5, -0.5), Vec3d(0.5, 0.5, -0.5), 0.125, 30, Color::brown()));
|
||||
viz.showWidget("con0", WCone(0.25, 0.125, 6, Color::azure()));
|
||||
viz.showWidget("con1", WCone(0.125, Point3d(0.5, -0.5, 0.5), Point3d(0.5, -1.0, 0.5), 6, Color::turquoise()));
|
||||
|
||||
viz.showWidget("text2d", WText("Different simple widgets", Point(20, 20), 20, Color::green()));
|
||||
viz.showWidget("text3d", WText3D("Simple 3D text", Point3d( 0.5, 0.5, 0.5), 0.125, false, Color::green()));
|
||||
|
||||
viz.showWidget("plane1", WPlane(Size2d(0.25, 0.75)));
|
||||
viz.showWidget("plane2", WPlane(Vec3d(0.5, -0.5, -0.5), Vec3d(0.0, 1.0, 1.0), Vec3d(1.0, 1.0, 0.0), Size2d(1.0, 0.5), Color::gold()));
|
||||
|
||||
viz.showWidget("grid1", WGrid(Vec2i(7,7), Vec2d::all(0.75), Color::gray()), Affine3d().translate(Vec3d(0.0, 0.0, -1.0)));
|
||||
|
||||
viz.spinOnce(500, true);
|
||||
viz.getWidget("text2d").cast<WText>().setText("Different simple widgets (updated)");
|
||||
viz.getWidget("text3d").cast<WText3D>().setText("Updated text 3D");
|
||||
viz.spinOnce(500, true);
|
||||
}
|
||||
|
||||
TEST(Viz, show_follower)
|
||||
{
|
||||
Viz3d viz("show_follower");
|
||||
|
||||
viz.showWidget("coos", WCoordinateSystem());
|
||||
viz.showWidget("cube", WCube());
|
||||
viz.showWidget("t3d_2", WText3D("Simple 3D follower", Point3d(-0.5, -0.5, 0.5), 0.125, true, Color::green()));
|
||||
viz.showWidget("text2d", WText("Follower: text always facing camera", Point(20, 20), 20, Color::green()));
|
||||
viz.setBackgroundMeshLab();
|
||||
viz.spinOnce(500, true);
|
||||
viz.getWidget("t3d_2").cast<WText3D>().setText("Updated follower 3D");
|
||||
viz.spinOnce(500, true);
|
||||
}
|
||||
|
||||
}} // namespace
|
|
@ -0,0 +1,58 @@
|
|||
Creating Widgets {#tutorial_creating_widgets}
|
||||
================
|
||||
|
||||
@prev_tutorial{tutorial_transformations}
|
||||
@next_tutorial{tutorial_histo3D}
|
||||
|
||||
Goal
|
||||
----
|
||||
|
||||
In this tutorial you will learn how to
|
||||
|
||||
- Create your own widgets using WidgetAccessor and VTK.
|
||||
- Show your widget in the visualization window.
|
||||
|
||||
Code
|
||||
----
|
||||
|
||||
You can download the code from [here ](https://github.com/opencv/opencv_contrib/tree/master/modules/viz/samples/creating_widgets.cpp).
|
||||
@include viz/samples/creating_widgets.cpp
|
||||
|
||||
Explanation
|
||||
-----------
|
||||
|
||||
Here is the general structure of the program:
|
||||
|
||||
- Extend Widget3D class to create a new 3D widget.
|
||||
@code{.cpp}
|
||||
class WTriangle : public viz::Widget3D
|
||||
{
|
||||
public:
|
||||
WTriangle(const Point3f &pt1, const Point3f &pt2, const Point3f &pt3, const viz::Color & color = viz::Color::white());
|
||||
};
|
||||
@endcode
|
||||
- Assign a VTK actor to the widget.
|
||||
@code{.cpp}
|
||||
// Store this actor in the widget in order that visualizer can access it
|
||||
viz::WidgetAccessor::setProp(*this, actor);
|
||||
@endcode
|
||||
- Set color of the widget.
|
||||
@code{.cpp}
|
||||
// Set the color of the widget. This has to be called after WidgetAccessor.
|
||||
setColor(color);
|
||||
@endcode
|
||||
- Construct a triangle widget and display it in the window.
|
||||
@code{.cpp}
|
||||
/// Create a triangle widget
|
||||
WTriangle tw(Point3f(0.0,0.0,0.0), Point3f(1.0,1.0,1.0), Point3f(0.0,1.0,0.0), viz::Color::red());
|
||||
|
||||
/// Show widget in the visualizer window
|
||||
myWindow.showWidget("TRIANGLE", tw);
|
||||
@endcode
|
||||
|
||||
Results
|
||||
-------
|
||||
|
||||
Here is the result of the program.
|
||||
|
||||
![](images/red_triangle.png)
|
After Width: | Height: | Size: 10 KiB |
|
@ -0,0 +1,53 @@
|
|||
Creating a 3D histogram {#tutorial_histo3D}
|
||||
================
|
||||
|
||||
@prev_tutorial{tutorial_creating_widgets}
|
||||
|
||||
Goal
|
||||
----
|
||||
|
||||
In this tutorial you will learn how to
|
||||
|
||||
- Create your own callback keyboard function for viz window.
|
||||
- Show your 3D histogram in a viz window.
|
||||
|
||||
Code
|
||||
----
|
||||
|
||||
You can download the code from [here ](https://github.com/opencv/opencv_contrib/tree/master/modules/viz/samples/histo3D.cpp).
|
||||
@include viz/samples/histo3D.cpp
|
||||
|
||||
Explanation
|
||||
-----------
|
||||
|
||||
Here is the general structure of the program:
|
||||
|
||||
- You can give full path to an image in command line
|
||||
@snippet histo3D.cpp command_line_parser
|
||||
|
||||
or without path, a synthetic image is generated with pixel values are a gaussian distribution @ref cv::RNG::fill center(60+/-10,40+/-5,50+/-20) in first quadrant,
|
||||
(160+/-20,10+/-5,50+/-10) in second quadrant, (90+/-10,100+/-20,50+/-20) in third quadrant, (100+/-10,10+/-5,150+/-40) in last quadrant.
|
||||
@snippet histo3D.cpp synthetic_image
|
||||
Image tridimensional histogram is calculated using opencv @ref cv::calcHist and @ref cv::normalize between 0 and 100.
|
||||
@snippet histo3D.cpp calchist_for_histo3d
|
||||
channel are 2, 1 and 0 to synchronise color with Viz axis color in objetc cv::viz::WCoordinateSystem.
|
||||
|
||||
A slidebar is inserted in image window. Init slidebar value is 90, it means that only histogram cell greater than 9/100000.0 (23 pixels for an 512X512 pixels) will be display.
|
||||
@snippet histo3D.cpp slide_bar_for_thresh
|
||||
We are ready to open a viz window with a callback function to capture keyboard event in viz window. Using @ref cv::viz::Viz3d::spinOnce enable keyboard event to be capture in @ref cv::imshow window too.
|
||||
@snippet histo3D.cpp manage_viz_imshow_window
|
||||
The function DrawHistogram3D processes histogram Mat to display it in a Viz window. Number of plan, row and column in [three dimensional Mat](@ref CVMat_Details ) can be found using this code :
|
||||
@snippet histo3D.cpp get_cube_size
|
||||
To get histogram value at a specific location we use @ref cv::Mat::at(int i0,int i1, int i2) method with three arguments k, i and j where k is plane number, i row number and j column number.
|
||||
@snippet histo3D.cpp get_cube_values
|
||||
|
||||
- Callback function
|
||||
Principle are as mouse callback function. Key code pressed is in field code of class @ref cv::viz::KeyboardEvent.
|
||||
@snippet histo3D.cpp viz_keyboard_callback
|
||||
|
||||
Results
|
||||
-------
|
||||
|
||||
Here is the result of the program with no argument and threshold equal to 50.
|
||||
|
||||
![](images/histo50.png)
|
After Width: | Height: | Size: 839 KiB |
After Width: | Height: | Size: 18 KiB |
After Width: | Height: | Size: 28 KiB |
After Width: | Height: | Size: 1.1 KiB |
After Width: | Height: | Size: 7.3 KiB |
|
@ -0,0 +1,66 @@
|
|||
Launching Viz {#tutorial_launching_viz}
|
||||
=============
|
||||
|
||||
@next_tutorial{tutorial_widget_pose}
|
||||
|
||||
Goal
|
||||
----
|
||||
|
||||
In this tutorial you will learn how to
|
||||
|
||||
- Open a visualization window.
|
||||
- Access a window by its name.
|
||||
- Start event loop.
|
||||
- Start event loop for a given amount of time.
|
||||
|
||||
Code
|
||||
----
|
||||
|
||||
You can download the code from [here ](https://github.com/opencv/opencv_contrib/tree/master/modules/viz/samples/launching_viz.cpp).
|
||||
@include viz/samples/launching_viz.cpp
|
||||
|
||||
Explanation
|
||||
-----------
|
||||
|
||||
Here is the general structure of the program:
|
||||
|
||||
- Create a window.
|
||||
@code{.cpp}
|
||||
/// Create a window
|
||||
viz::Viz3d myWindow("Viz Demo");
|
||||
@endcode
|
||||
- Start event loop. This event loop will run until user terminates it by pressing **e**, **E**,
|
||||
**q**, **Q**.
|
||||
@code{.cpp}
|
||||
/// Start event loop
|
||||
myWindow.spin();
|
||||
@endcode
|
||||
- Access same window via its name. Since windows are implicitly shared, **sameWindow** is exactly
|
||||
the same with **myWindow**. If the name does not exist, a new window is created.
|
||||
@code{.cpp}
|
||||
/// Access window via its name
|
||||
viz::Viz3d sameWindow = viz::getWindowByName("Viz Demo");
|
||||
@endcode
|
||||
- Start a controlled event loop. Once it starts, **wasStopped** is set to false. Inside the while
|
||||
loop, in each iteration, **spinOnce** is called to prevent event loop from completely stopping.
|
||||
Inside the while loop, user can execute other statements including those which interact with the
|
||||
window.
|
||||
@code{.cpp}
|
||||
/// Event loop is over when pressed q, Q, e, E
|
||||
/// Start event loop once for 1 millisecond
|
||||
sameWindow.spinOnce(1, true);
|
||||
while(!sameWindow.wasStopped())
|
||||
{
|
||||
/// Interact with window
|
||||
|
||||
/// Event loop for 1 millisecond
|
||||
sameWindow.spinOnce(1, true);
|
||||
}
|
||||
@endcode
|
||||
|
||||
Results
|
||||
-------
|
||||
|
||||
Here is the result of the program.
|
||||
|
||||
![](images/window_demo.png)
|
|
@ -0,0 +1,52 @@
|
|||
OpenCV Viz {#tutorial_table_of_content_viz}
|
||||
==========
|
||||
|
||||
- @subpage tutorial_launching_viz
|
||||
|
||||
*Languages:* C++
|
||||
|
||||
*Compatibility:* \> OpenCV 3.0.0
|
||||
|
||||
*Author:* Ozan Tonkal
|
||||
|
||||
You will learn how to launch a viz window.
|
||||
|
||||
- @subpage tutorial_widget_pose
|
||||
|
||||
*Languages:* C++
|
||||
|
||||
*Compatibility:* \> OpenCV 3.0.0
|
||||
|
||||
*Author:* Ozan Tonkal
|
||||
|
||||
You will learn how to change pose of a widget.
|
||||
|
||||
- @subpage tutorial_transformations
|
||||
|
||||
*Languages:* C++
|
||||
|
||||
*Compatibility:* \> OpenCV 3.0.0
|
||||
|
||||
*Author:* Ozan Tonkal
|
||||
|
||||
You will learn how to transform between global and camera frames.
|
||||
|
||||
- @subpage tutorial_creating_widgets
|
||||
|
||||
*Languages:* C++
|
||||
|
||||
*Compatibility:* \> OpenCV 3.0.0
|
||||
|
||||
*Author:* Ozan Tonkal
|
||||
|
||||
You will learn how to create your own widgets.
|
||||
|
||||
- @subpage tutorial_histo3D
|
||||
|
||||
*Languages:* C++
|
||||
|
||||
*Compatibility:* \> OpenCV 3.0.0
|
||||
|
||||
*Author:* Laurent Berger
|
||||
|
||||
You will learn how to plot a 3D histogram.
|
After Width: | Height: | Size: 18 KiB |
After Width: | Height: | Size: 13 KiB |
|
@ -0,0 +1,91 @@
|
|||
Transformations {#tutorial_transformations}
|
||||
===============
|
||||
|
||||
@prev_tutorial{tutorial_widget_pose}
|
||||
@next_tutorial{tutorial_creating_widgets}
|
||||
|
||||
Goal
|
||||
----
|
||||
|
||||
In this tutorial you will learn how to
|
||||
|
||||
- How to use makeTransformToGlobal to compute pose
|
||||
- How to use makeCameraPose and Viz3d::setViewerPose
|
||||
- How to visualize camera position by axes and by viewing frustum
|
||||
|
||||
Code
|
||||
----
|
||||
|
||||
You can download the code from [here ](https://github.com/opencv/opencv_contrib/tree/master/modules/viz/samples/transformations.cpp).
|
||||
@include viz/samples/transformations.cpp
|
||||
|
||||
Explanation
|
||||
-----------
|
||||
|
||||
Here is the general structure of the program:
|
||||
|
||||
- Create a visualization window.
|
||||
@code{.cpp}
|
||||
/// Create a window
|
||||
viz::Viz3d myWindow("Transformations");
|
||||
@endcode
|
||||
- Get camera pose from camera position, camera focal point and y direction.
|
||||
@code{.cpp}
|
||||
/// Let's assume camera has the following properties
|
||||
Point3f cam_pos(3.0f,3.0f,3.0f), cam_focal_point(3.0f,3.0f,2.0f), cam_y_dir(-1.0f,0.0f,0.0f);
|
||||
|
||||
/// We can get the pose of the cam using makeCameraPose
|
||||
Affine3f cam_pose = viz::makeCameraPose(cam_pos, cam_focal_point, cam_y_dir);
|
||||
@endcode
|
||||
- Obtain transform matrix knowing the axes of camera coordinate system.
|
||||
@code{.cpp}
|
||||
/// We can get the transformation matrix from camera coordinate system to global using
|
||||
/// - makeTransformToGlobal. We need the axes of the camera
|
||||
Affine3f transform = viz::makeTransformToGlobal(Vec3f(0.0f,-1.0f,0.0f), Vec3f(-1.0f,0.0f,0.0f), Vec3f(0.0f,0.0f,-1.0f), cam_pos);
|
||||
@endcode
|
||||
- Create a cloud widget from bunny.ply file
|
||||
@code{.cpp}
|
||||
/// Create a cloud widget.
|
||||
Mat bunny_cloud = cvcloud_load();
|
||||
viz::WCloud cloud_widget(bunny_cloud, viz::Color::green());
|
||||
@endcode
|
||||
- Given the pose in camera coordinate system, estimate the global pose.
|
||||
@code{.cpp}
|
||||
/// Pose of the widget in camera frame
|
||||
Affine3f cloud_pose = Affine3f().translate(Vec3f(0.0f,0.0f,3.0f));
|
||||
/// Pose of the widget in global frame
|
||||
Affine3f cloud_pose_global = transform * cloud_pose;
|
||||
@endcode
|
||||
- If the view point is set to be global, visualize camera coordinate frame and viewing frustum.
|
||||
@code{.cpp}
|
||||
/// Visualize camera frame
|
||||
if (!camera_pov)
|
||||
{
|
||||
viz::WCameraPosition cpw(0.5); // Coordinate axes
|
||||
viz::WCameraPosition cpw_frustum(Vec2f(0.889484, 0.523599)); // Camera frustum
|
||||
myWindow.showWidget("CPW", cpw, cam_pose);
|
||||
myWindow.showWidget("CPW_FRUSTUM", cpw_frustum, cam_pose);
|
||||
}
|
||||
@endcode
|
||||
- Visualize the cloud widget with the estimated global pose
|
||||
@code{.cpp}
|
||||
/// Visualize widget
|
||||
myWindow.showWidget("bunny", cloud_widget, cloud_pose_global);
|
||||
@endcode
|
||||
- If the view point is set to be camera's, set viewer pose to **cam_pose**.
|
||||
@code{.cpp}
|
||||
/// Set the viewer pose to that of camera
|
||||
if (camera_pov)
|
||||
myWindow.setViewerPose(cam_pose);
|
||||
@endcode
|
||||
|
||||
Results
|
||||
-------
|
||||
|
||||
-# Here is the result from the camera point of view.
|
||||
|
||||
![](images/camera_view_point.png)
|
||||
|
||||
-# Here is the result from global point of view.
|
||||
|
||||
![](images/global_view_point.png)
|
After Width: | Height: | Size: 40 KiB |
|
@ -0,0 +1,88 @@
|
|||
Pose of a widget {#tutorial_widget_pose}
|
||||
================
|
||||
|
||||
@prev_tutorial{tutorial_launching_viz}
|
||||
@next_tutorial{tutorial_transformations}
|
||||
|
||||
Goal
|
||||
----
|
||||
|
||||
In this tutorial you will learn how to
|
||||
|
||||
- Add widgets to the visualization window
|
||||
- Use Affine3 to set pose of a widget
|
||||
- Rotating and translating a widget along an axis
|
||||
|
||||
Code
|
||||
----
|
||||
|
||||
You can download the code from [here ](https://github.com/opencv/opencv_contrib/tree/master/modules/viz/samples/widget_pose.cpp).
|
||||
@include viz/samples/widget_pose.cpp
|
||||
|
||||
Explanation
|
||||
-----------
|
||||
|
||||
Here is the general structure of the program:
|
||||
|
||||
- Create a visualization window.
|
||||
@code{.cpp}
|
||||
/// Create a window
|
||||
viz::Viz3d myWindow("Coordinate Frame");
|
||||
@endcode
|
||||
- Show coordinate axes in the window using CoordinateSystemWidget.
|
||||
@code{.cpp}
|
||||
/// Add coordinate axes
|
||||
myWindow.showWidget("Coordinate Widget", viz::WCoordinateSystem());
|
||||
@endcode
|
||||
- Display a line representing the axis (1,1,1).
|
||||
@code{.cpp}
|
||||
/// Add line to represent (1,1,1) axis
|
||||
viz::WLine axis(Point3f(-1.0f,-1.0f,-1.0f), Point3f(1.0f,1.0f,1.0f));
|
||||
axis.setRenderingProperty(viz::LINE_WIDTH, 4.0);
|
||||
myWindow.showWidget("Line Widget", axis);
|
||||
@endcode
|
||||
- Construct a cube.
|
||||
@code{.cpp}
|
||||
/// Construct a cube widget
|
||||
viz::WCube cube_widget(Point3f(0.5,0.5,0.0), Point3f(0.0,0.0,-0.5), true, viz::Color::blue());
|
||||
cube_widget.setRenderingProperty(viz::LINE_WIDTH, 4.0);
|
||||
myWindow.showWidget("Cube Widget", cube_widget);
|
||||
@endcode
|
||||
- Create rotation matrix from rodrigues vector
|
||||
@code{.cpp}
|
||||
/// Rotate around (1,1,1)
|
||||
rot_vec.at<float>(0,0) += CV_PI * 0.01f;
|
||||
rot_vec.at<float>(0,1) += CV_PI * 0.01f;
|
||||
rot_vec.at<float>(0,2) += CV_PI * 0.01f;
|
||||
|
||||
...
|
||||
|
||||
Mat rot_mat;
|
||||
Rodrigues(rot_vec, rot_mat);
|
||||
@endcode
|
||||
- Use Affine3f to set pose of the cube.
|
||||
@code{.cpp}
|
||||
/// Construct pose
|
||||
Affine3f pose(rot_mat, Vec3f(translation, translation, translation));
|
||||
myWindow.setWidgetPose("Cube Widget", pose);
|
||||
@endcode
|
||||
- Animate the rotation using wasStopped and spinOnce
|
||||
@code{.cpp}
|
||||
while(!myWindow.wasStopped())
|
||||
{
|
||||
...
|
||||
|
||||
myWindow.spinOnce(1, true);
|
||||
}
|
||||
@endcode
|
||||
|
||||
Results
|
||||
-------
|
||||
|
||||
Here is the result of the program.
|
||||
|
||||
\htmlonly
|
||||
<div align="center">
|
||||
<iframe width="420" height="315" src="https://www.youtube.com/embed/22HKMN657U0" frameborder="0" allowfullscreen></iframe>
|
||||
</div>
|
||||
\endhtmlonly
|
|
@ -0,0 +1,40 @@
|
|||
set(the_description "WeChat QR code Detector")
|
||||
ocv_define_module(wechat_qrcode opencv_core opencv_imgproc opencv_objdetect opencv_dnn WRAP java objc python js)
|
||||
|
||||
# iconv support isn't automatic on some systems
|
||||
if(CMAKE_VERSION VERSION_GREATER "3.11")
|
||||
find_package(Iconv QUIET)
|
||||
if(Iconv_FOUND)
|
||||
ocv_target_link_libraries(${the_module} Iconv::Iconv)
|
||||
else()
|
||||
ocv_target_compile_definitions(${the_module} PRIVATE "NO_ICONV=1")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# need to change
|
||||
set(wechat_qrcode_commit_hash "a8b69ccc738421293254aec5ddb38bd523503252")
|
||||
set(hash_detect_caffemodel "238e2b2d6f3c18d6c3a30de0c31e23cf")
|
||||
set(hash_detect_prototxt "6fb4976b32695f9f5c6305c19f12537d")
|
||||
set(hash_sr_caffemodel "cbfcd60361a73beb8c583eea7e8e6664")
|
||||
set(hash_sr_prototxt "69db99927a70df953b471daaba03fbef")
|
||||
|
||||
set(model_types caffemodel prototxt)
|
||||
set(model_names detect sr)
|
||||
|
||||
foreach(model_name ${model_names})
|
||||
foreach(model_type ${model_types})
|
||||
ocv_download(FILENAME ${model_name}.${model_type}
|
||||
HASH ${hash_${model_name}_${model_type}}
|
||||
URL
|
||||
"${OPENCV_WECHAT_QRCODE_URL}"
|
||||
"$ENV{OPENCV_WECHAT_QRCODE_URL}"
|
||||
"https://raw.githubusercontent.com/WeChatCV/opencv_3rdparty/${wechat_qrcode_commit_hash}/"
|
||||
DESTINATION_DIR "${CMAKE_BINARY_DIR}/downloads/wechat_qrcode"
|
||||
ID "wechat_qrcode"
|
||||
RELATIVE_URL
|
||||
STATUS res)
|
||||
if(NOT res)
|
||||
message(WARNING "WeChatQRCode: Can't get ${model_name} ${model_type} file for wechat qrcode.")
|
||||
endif()
|
||||
endforeach()
|
||||
endforeach()
|
|
@ -0,0 +1,253 @@
|
|||
Tencent is pleased to support the open source community by making WeChat QRCode available.
|
||||
|
||||
Copyright (C) 2021 THL A29 Limited, a Tencent company. All rights reserved.
|
||||
The below software in this distribution may have been modified by THL A29 Limited ("Tencent Modifications").
|
||||
All Tencent Modifications are Copyright (C) THL A29 Limited.
|
||||
|
||||
WeChat QRCode is licensed under the Apache License Version 2.0, except for the third-party components listed below.
|
||||
|
||||
Terms of the Apache License Version 2.0
|
||||
--------------------------------------------------------------------
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
|
||||
|
||||
Other dependencies and licenses:
|
||||
|
||||
Open Source Software Licensed under the Apache License Version 2.0:
|
||||
--------------------------------------------------------------------
|
||||
1. zxing
|
||||
Copyright (c) zxing authors and contributors
|
||||
Please note this software may have been modified by Tencent.
|
||||
|
||||
Terms of the Apache License Version 2.0:
|
||||
--------------------------------------------------------------------
|
||||
Apache License
|
||||
|
||||
Version 2.0, January 2004
|
||||
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions:
|
||||
|
||||
You must give any other recipients of the Work or Derivative Works a copy of this License; and
|
||||
You must cause any modified files to carry prominent notices stating that You changed the files; and
|
||||
You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and
|
||||
If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
|
@ -0,0 +1,12 @@
|
|||
WeChat QR code detector for detecting and parsing QR code.
|
||||
================================================
|
||||
|
||||
WeChat QR code detector is a high-performance and lightweight QR code detect and decode library, which is contributed by WeChat Computer Vision Team (WeChatCV). It has been widely used in various Tencent applications, including WeChat, WeCom, QQ, QQ Browser, and so on. There are four primary features of WeChat QR code detector:
|
||||
|
||||
1. CNN-based QR code detector. Different from the traditional detector, we introduce a tiny CNN model for multiple code detection. The detector is based on SSD architecture with a MobileNetV2-like backbone, which is run on caffe inference framework.
|
||||
|
||||
2. CNN-based QR code enhancement. To improve the performance of tiny QR code, we design a lighten super-resolution CNN model for QR code, called QRSR. Depth-wise convolution, DenseNet concat and deconvolution are the core techniques in the QRSR model.
|
||||
|
||||
3. More robust finder pattern detection. Besides traditional horizontal line searching, we propose an area size based finder pattern detection method. we calculate the area size of black and white block to locate the finder pattern by the pre-computed connected cells.
|
||||
|
||||
4. Massive engineering optimization. Based on [zxing-cpp](https://github.com/glassechidna/zxing-cpp), we conduct massive engineering optimization to boost the decoding success rate, such as trying more binarization methods, supporting N:1:3:1:1 finder pattern detection, finding more alignment pattern, clustering similar size finder pattern, and etc.
|
|
@ -0,0 +1,77 @@
|
|||
// This file is part of OpenCV project.
|
||||
// It is subject to the license terms in the LICENSE file found in the top-level directory
|
||||
// of this distribution and at http://opencv.org/license.html.
|
||||
//
|
||||
// Tencent is pleased to support the open source community by making WeChat QRCode available.
|
||||
// Copyright (C) 2020 THL A29 Limited, a Tencent company. All rights reserved.
|
||||
|
||||
#ifndef __OPENCV_WECHAT_QRCODE_HPP__
|
||||
#define __OPENCV_WECHAT_QRCODE_HPP__
|
||||
#include "opencv2/core.hpp"
|
||||
/** @defgroup wechat_qrcode WeChat QR code detector for detecting and parsing QR code.
|
||||
*/
|
||||
namespace cv {
|
||||
namespace wechat_qrcode {
|
||||
//! @addtogroup wechat_qrcode
|
||||
//! @{
|
||||
/**
|
||||
* @brief WeChat QRCode includes two CNN-based models:
|
||||
* A object detection model and a super resolution model.
|
||||
* Object detection model is applied to detect QRCode with the bounding box.
|
||||
* super resolution model is applied to zoom in QRCode when it is small.
|
||||
*
|
||||
*/
|
||||
class CV_EXPORTS_W WeChatQRCode {
|
||||
public:
|
||||
/**
|
||||
* @brief Initialize the WeChatQRCode.
|
||||
* It includes two models, which are packaged with caffe format.
|
||||
* Therefore, there are prototxt and caffe models (In total, four paramenters).
|
||||
*
|
||||
* @param detector_prototxt_path prototxt file path for the detector
|
||||
* @param detector_caffe_model_path caffe model file path for the detector
|
||||
* @param super_resolution_prototxt_path prototxt file path for the super resolution model
|
||||
* @param super_resolution_caffe_model_path caffe file path for the super resolution model
|
||||
*/
|
||||
CV_WRAP WeChatQRCode(const std::string& detector_prototxt_path = "",
|
||||
const std::string& detector_caffe_model_path = "",
|
||||
const std::string& super_resolution_prototxt_path = "",
|
||||
const std::string& super_resolution_caffe_model_path = "");
|
||||
~WeChatQRCode(){};
|
||||
|
||||
/**
|
||||
* @brief Both detects and decodes QR code.
|
||||
* To simplify the usage, there is a only API: detectAndDecode
|
||||
*
|
||||
* @param img supports grayscale or color (BGR) image.
|
||||
* @param points optional output array of vertices of the found QR code quadrangle. Will be
|
||||
* empty if not found.
|
||||
* @return list of decoded string.
|
||||
*/
|
||||
CV_WRAP std::vector<std::string> detectAndDecode(InputArray img, OutputArrayOfArrays points = noArray());
|
||||
|
||||
/**
|
||||
* @brief set scale factor
|
||||
* QR code detector use neural network to detect QR.
|
||||
* Before running the neural network, the input image is pre-processed by scaling.
|
||||
* By default, the input image is scaled to an image with an area of 160000 pixels.
|
||||
* The scale factor allows to use custom scale the input image:
|
||||
* width = scaleFactor*width
|
||||
* height = scaleFactor*width
|
||||
*
|
||||
* scaleFactor valuse must be > 0 and <= 1, otherwise the scaleFactor value is set to -1
|
||||
* and use default scaled to an image with an area of 160000 pixels.
|
||||
*/
|
||||
CV_WRAP void setScaleFactor(float _scalingFactor);
|
||||
|
||||
CV_WRAP float getScaleFactor();
|
||||
|
||||
protected:
|
||||
class Impl;
|
||||
Ptr<Impl> p;
|
||||
};
|
||||
|
||||
//! @}
|
||||
} // namespace wechat_qrcode
|
||||
} // namespace cv
|
||||
#endif // __OPENCV_WECHAT_QRCODE_HPP__
|
|
@ -0,0 +1,53 @@
|
|||
import cv2
|
||||
import sys
|
||||
|
||||
print(sys.argv[0])
|
||||
print('A demo program of WeChat QRCode Detector:')
|
||||
camIdx = -1
|
||||
if len(sys.argv) > 1:
|
||||
if sys.argv[1] == "-camera":
|
||||
camIdx = int(sys.argv[2]) if len(sys.argv)>2 else 0
|
||||
img = cv2.imread(sys.argv[1])
|
||||
else:
|
||||
print(" Usage: " + sys.argv[0] + " <input_image>")
|
||||
exit(0)
|
||||
|
||||
# For python API generator, it follows the template: {module_name}_{class_name},
|
||||
# so it is a little weird.
|
||||
# The model is downloaded to ${CMAKE_BINARY_DIR}/downloads/wechat_qrcode if cmake runs without warnings,
|
||||
# otherwise you can download them from https://github.com/WeChatCV/opencv_3rdparty/tree/wechat_qrcode.
|
||||
try:
|
||||
detector = cv2.wechat_qrcode_WeChatQRCode(
|
||||
"detect.prototxt", "detect.caffemodel", "sr.prototxt", "sr.caffemodel")
|
||||
except:
|
||||
print("---------------------------------------------------------------")
|
||||
print("Failed to initialize WeChatQRCode.")
|
||||
print("Please, download 'detector.*' and 'sr.*' from")
|
||||
print("https://github.com/WeChatCV/opencv_3rdparty/tree/wechat_qrcode")
|
||||
print("and put them into the current directory.")
|
||||
print("---------------------------------------------------------------")
|
||||
exit(0)
|
||||
|
||||
prevstr = ""
|
||||
|
||||
if camIdx < 0:
|
||||
res, points = detector.detectAndDecode(img)
|
||||
print(res,points)
|
||||
else:
|
||||
cap = cv2.VideoCapture(camIdx)
|
||||
while True:
|
||||
res, img = cap.read()
|
||||
if img is None:
|
||||
break
|
||||
res, points = detector.detectAndDecode(img)
|
||||
for t in res:
|
||||
if t != prevstr:
|
||||
print(t)
|
||||
if res:
|
||||
prevstr = res[-1]
|
||||
cv2.imshow("image", img)
|
||||
if cv2.waitKey(30) >= 0:
|
||||
break
|
||||
# When everything done, release the capture
|
||||
cap.release()
|
||||
cv2.destroyAllWindows()
|
|
@ -0,0 +1,70 @@
|
|||
#include <iostream>
|
||||
#include <opencv2/core.hpp>
|
||||
#include <opencv2/highgui.hpp>
|
||||
#include <opencv2/imgproc.hpp>
|
||||
|
||||
using namespace std;
|
||||
using namespace cv;
|
||||
|
||||
#include <opencv2/wechat_qrcode.hpp>
|
||||
int main(int argc, char* argv[]) {
|
||||
cout << endl << argv[0] << endl << endl;
|
||||
cout << "A demo program of WeChat QRCode Detector: " << endl;
|
||||
|
||||
Mat img;
|
||||
int camIdx = -1;
|
||||
if (argc > 1) {
|
||||
bool live = strcmp(argv[1], "-camera") == 0;
|
||||
if (live) {
|
||||
camIdx = argc > 2 ? atoi(argv[2]) : 0;
|
||||
} else {
|
||||
img = imread(argv[1]);
|
||||
}
|
||||
} else {
|
||||
cout << " Usage: " << argv[0] << " <input_image>" << endl;
|
||||
return 0;
|
||||
}
|
||||
// The model is downloaded to ${CMAKE_BINARY_DIR}/downloads/wechat_qrcode if cmake runs without warnings,
|
||||
// otherwise you can download them from https://github.com/WeChatCV/opencv_3rdparty/tree/wechat_qrcode.
|
||||
Ptr<wechat_qrcode::WeChatQRCode> detector;
|
||||
|
||||
try {
|
||||
detector = makePtr<wechat_qrcode::WeChatQRCode>("detect.prototxt", "detect.caffemodel",
|
||||
"sr.prototxt", "sr.caffemodel");
|
||||
} catch (const std::exception& e) {
|
||||
cout <<
|
||||
"\n---------------------------------------------------------------\n"
|
||||
"Failed to initialize WeChatQRCode.\n"
|
||||
"Please, download 'detector.*' and 'sr.*' from\n"
|
||||
"https://github.com/WeChatCV/opencv_3rdparty/tree/wechat_qrcode\n"
|
||||
"and put them into the current directory.\n"
|
||||
"---------------------------------------------------------------\n";
|
||||
cout << e.what() << endl;
|
||||
return 0;
|
||||
}
|
||||
string prevstr = "";
|
||||
vector<Mat> points;
|
||||
|
||||
if (camIdx < 0) {
|
||||
auto res = detector->detectAndDecode(img, points);
|
||||
for (const auto& t : res) cout << t << endl;
|
||||
} else {
|
||||
VideoCapture cap(camIdx);
|
||||
for(;;) {
|
||||
cap >> img;
|
||||
if (img.empty())
|
||||
break;
|
||||
auto res = detector->detectAndDecode(img, points);
|
||||
for (const auto& t : res) {
|
||||
if (t != prevstr)
|
||||
cout << t << endl;
|
||||
}
|
||||
if (!res.empty())
|
||||
prevstr = res.back();
|
||||
imshow("image", img);
|
||||
if (waitKey(30) >= 0)
|
||||
break;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,67 @@
|
|||
#include <iostream>
|
||||
#include <opencv2/core.hpp>
|
||||
#include <opencv2/highgui.hpp>
|
||||
#include <opencv2/imgproc.hpp>
|
||||
|
||||
using namespace std;
|
||||
using namespace cv;
|
||||
|
||||
#include <opencv2/wechat_qrcode.hpp>
|
||||
|
||||
int main(int argc, char* argv[]) {
|
||||
cout << endl << argv[0] << endl << endl;
|
||||
cout << "A demo program of WeChat QRCode Detector: " << endl;
|
||||
|
||||
Mat img;
|
||||
int camIdx = -1;
|
||||
if (argc > 1) {
|
||||
bool live = strcmp(argv[1], "-camera") == 0;
|
||||
if (live) {
|
||||
camIdx = argc > 2 ? atoi(argv[2]) : 0;
|
||||
} else {
|
||||
img = imread(argv[1]);
|
||||
}
|
||||
} else {
|
||||
cout << " Usage: " << argv[0] << " <input_image>" << endl;
|
||||
return 0;
|
||||
}
|
||||
// The model is downloaded to ${CMAKE_BINARY_DIR}/downloads/wechat_qrcode if cmake runs without warnings,
|
||||
// otherwise you can download them from https://github.com/WeChatCV/opencv_3rdparty/tree/wechat_qrcode.
|
||||
Ptr<wechat_qrcode::WeChatQRCode> detector;
|
||||
|
||||
try {
|
||||
detector = makePtr<wechat_qrcode::WeChatQRCode>("", "", "", "");
|
||||
} catch (const std::exception& e) {
|
||||
cout <<
|
||||
"\n---------------------------------------------------------------\n"
|
||||
"Failed to initialize WeChatQRCode.\n"
|
||||
"---------------------------------------------------------------\n";
|
||||
cout << e.what() << endl;
|
||||
return 0;
|
||||
}
|
||||
string prevstr = "";
|
||||
vector<Mat> points;
|
||||
|
||||
if (camIdx < 0) {
|
||||
auto res = detector->detectAndDecode(img, points);
|
||||
for (const auto& t : res) cout << t << endl;
|
||||
} else {
|
||||
VideoCapture cap(camIdx);
|
||||
for(;;) {
|
||||
cap >> img;
|
||||
if (img.empty())
|
||||
break;
|
||||
auto res = detector->detectAndDecode(img, points);
|
||||
for (const auto& t : res) {
|
||||
if (t != prevstr)
|
||||
cout << t << endl;
|
||||
}
|
||||
if (!res.empty())
|
||||
prevstr = res.back();
|
||||
imshow("image", img);
|
||||
if (waitKey(30) >= 0)
|
||||
break;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,50 @@
|
|||
import cv2
|
||||
import sys
|
||||
|
||||
print(sys.argv[0])
|
||||
print('A demo program of WeChat QRCode Detector:')
|
||||
camIdx = -1
|
||||
if len(sys.argv) > 1:
|
||||
if sys.argv[1] == "-camera":
|
||||
camIdx = int(sys.argv[2]) if len(sys.argv)>2 else 0
|
||||
img = cv2.imread(sys.argv[1])
|
||||
else:
|
||||
print(" Usage: " + sys.argv[0] + " <input_image>")
|
||||
exit(0)
|
||||
|
||||
# For python API generator, it follows the template: {module_name}_{class_name},
|
||||
# so it is a little weird.
|
||||
# The model is downloaded to ${CMAKE_BINARY_DIR}/downloads/wechat_qrcode if cmake runs without warnings,
|
||||
# otherwise you can download them from https://github.com/WeChatCV/opencv_3rdparty/tree/wechat_qrcode.
|
||||
try:
|
||||
detector = cv2.wechat_qrcode_WeChatQRCode(
|
||||
"", "", "", "")
|
||||
except:
|
||||
print("---------------------------------------------------------------")
|
||||
print("Failed to initialize WeChatQRCode.")
|
||||
print("---------------------------------------------------------------")
|
||||
exit(0)
|
||||
|
||||
prevstr = ""
|
||||
|
||||
if camIdx < 0:
|
||||
res, points = detector.detectAndDecode(img)
|
||||
print(res,points)
|
||||
else:
|
||||
cap = cv2.VideoCapture(camIdx)
|
||||
while True:
|
||||
res, img = cap.read()
|
||||
if img is None:
|
||||
break
|
||||
res, points = detector.detectAndDecode(img)
|
||||
for t in res:
|
||||
if t != prevstr:
|
||||
print(t)
|
||||
if res:
|
||||
prevstr = res[-1]
|
||||
cv2.imshow("image", img)
|
||||
if cv2.waitKey(30) >= 0:
|
||||
break
|
||||
# When everything done, release the capture
|
||||
cap.release()
|
||||
cv2.destroyAllWindows()
|
|
@ -0,0 +1,70 @@
|
|||
// This file is part of OpenCV project.
|
||||
// It is subject to the license terms in the LICENSE file found in the top-level directory
|
||||
// of this distribution and at http://opencv.org/license.html.
|
||||
//
|
||||
// Tencent is pleased to support the open source community by making WeChat QRCode available.
|
||||
// Copyright (C) 2020 THL A29 Limited, a Tencent company. All rights reserved.
|
||||
#include "precomp.hpp"
|
||||
#include "binarizermgr.hpp"
|
||||
#include "imgsource.hpp"
|
||||
|
||||
|
||||
using zxing::Binarizer;
|
||||
using zxing::LuminanceSource;
|
||||
namespace cv {
|
||||
namespace wechat_qrcode {
|
||||
BinarizerMgr::BinarizerMgr() : m_iNowRotateIndex(0), m_iNextOnceBinarizer(-1) {
|
||||
m_vecRotateBinarizer.push_back(Hybrid);
|
||||
m_vecRotateBinarizer.push_back(FastWindow);
|
||||
m_vecRotateBinarizer.push_back(SimpleAdaptive);
|
||||
m_vecRotateBinarizer.push_back(AdaptiveThreshold);
|
||||
}
|
||||
|
||||
BinarizerMgr::~BinarizerMgr() {}
|
||||
|
||||
zxing::Ref<Binarizer> BinarizerMgr::Binarize(zxing::Ref<LuminanceSource> source) {
|
||||
BINARIZER binarizerIdx = m_vecRotateBinarizer[m_iNowRotateIndex];
|
||||
if (m_iNextOnceBinarizer >= 0) {
|
||||
binarizerIdx = (BINARIZER)m_iNextOnceBinarizer;
|
||||
}
|
||||
|
||||
zxing::Ref<Binarizer> binarizer;
|
||||
switch (binarizerIdx) {
|
||||
case Hybrid:
|
||||
binarizer = new zxing::HybridBinarizer(source);
|
||||
break;
|
||||
case FastWindow:
|
||||
binarizer = new zxing::FastWindowBinarizer(source);
|
||||
break;
|
||||
case SimpleAdaptive:
|
||||
binarizer = new zxing::SimpleAdaptiveBinarizer(source);
|
||||
break;
|
||||
case AdaptiveThreshold:
|
||||
binarizer = new zxing::AdaptiveThresholdMeanBinarizer(source);
|
||||
break;
|
||||
default:
|
||||
binarizer = new zxing::HybridBinarizer(source);
|
||||
break;
|
||||
}
|
||||
|
||||
return binarizer;
|
||||
}
|
||||
|
||||
void BinarizerMgr::SwitchBinarizer() {
|
||||
m_iNowRotateIndex = (m_iNowRotateIndex + 1) % m_vecRotateBinarizer.size();
|
||||
}
|
||||
|
||||
int BinarizerMgr::GetCurBinarizer() {
|
||||
if (m_iNextOnceBinarizer != -1) return m_iNextOnceBinarizer;
|
||||
return m_vecRotateBinarizer[m_iNowRotateIndex];
|
||||
}
|
||||
|
||||
void BinarizerMgr::SetNextOnceBinarizer(int iBinarizerIndex) {
|
||||
m_iNextOnceBinarizer = iBinarizerIndex;
|
||||
}
|
||||
|
||||
void BinarizerMgr::SetBinarizer(vector<BINARIZER> vecRotateBinarizer) {
|
||||
m_vecRotateBinarizer = vecRotateBinarizer;
|
||||
}
|
||||
} // namespace wechat_qrcode
|
||||
} // namespace cv
|
|
@ -0,0 +1,51 @@
|
|||
// This file is part of OpenCV project.
|
||||
// It is subject to the license terms in the LICENSE file found in the top-level directory
|
||||
// of this distribution and at http://opencv.org/license.html.
|
||||
//
|
||||
// Tencent is pleased to support the open source community by making WeChat QRCode available.
|
||||
// Copyright (C) 2020 THL A29 Limited, a Tencent company. All rights reserved.
|
||||
|
||||
#ifndef __OPENCV_WECHAT_QRCODE_BINARIZERMGR_HPP__
|
||||
#define __OPENCV_WECHAT_QRCODE_BINARIZERMGR_HPP__
|
||||
|
||||
#include "zxing/binarizer.hpp"
|
||||
#include "zxing/common/binarizer/adaptive_threshold_mean_binarizer.hpp"
|
||||
#include "zxing/common/counted.hpp"
|
||||
#include "zxing/common/binarizer/fast_window_binarizer.hpp"
|
||||
#include "zxing/common/binarizer/hybrid_binarizer.hpp"
|
||||
#include "zxing/common/binarizer/simple_adaptive_binarizer.hpp"
|
||||
#include "zxing/zxing.hpp"
|
||||
|
||||
namespace cv {
|
||||
namespace wechat_qrcode {
|
||||
class BinarizerMgr {
|
||||
public:
|
||||
enum BINARIZER {
|
||||
Hybrid = 0,
|
||||
FastWindow = 1,
|
||||
SimpleAdaptive = 2,
|
||||
AdaptiveThreshold = 3
|
||||
};
|
||||
|
||||
public:
|
||||
BinarizerMgr();
|
||||
~BinarizerMgr();
|
||||
|
||||
zxing::Ref<zxing::Binarizer> Binarize(zxing::Ref<zxing::LuminanceSource> source);
|
||||
|
||||
void SwitchBinarizer();
|
||||
|
||||
int GetCurBinarizer();
|
||||
|
||||
void SetNextOnceBinarizer(int iBinarizerIndex);
|
||||
|
||||
void SetBinarizer(vector<BINARIZER> vecRotateBinarizer);
|
||||
|
||||
private:
|
||||
int m_iNowRotateIndex;
|
||||
int m_iNextOnceBinarizer;
|
||||
vector<BINARIZER> m_vecRotateBinarizer;
|
||||
};
|
||||
} // namespace wechat_qrcode
|
||||
} // namespace cv
|
||||
#endif // __OPENCV_WECHAT_QRCODE_BINARIZERMGR_HPP__
|
|
@ -0,0 +1,92 @@
|
|||
// This file is part of OpenCV project.
|
||||
// It is subject to the license terms in the LICENSE file found in the top-level directory
|
||||
// of this distribution and at http://opencv.org/license.html.
|
||||
//
|
||||
// Tencent is pleased to support the open source community by making WeChat QRCode available.
|
||||
// Copyright (C) 2020 THL A29 Limited, a Tencent company. All rights reserved.
|
||||
#include "precomp.hpp"
|
||||
#include "decodermgr.hpp"
|
||||
|
||||
|
||||
using zxing::ArrayRef;
|
||||
using zxing::BinaryBitmap;
|
||||
using zxing::DecodeHints;
|
||||
using zxing::ErrorHandler;
|
||||
using zxing::LuminanceSource;
|
||||
using zxing::Ref;
|
||||
using zxing::Result;
|
||||
using zxing::UnicomBlock;
|
||||
namespace cv {
|
||||
namespace wechat_qrcode {
|
||||
int DecoderMgr::decodeImage(cv::Mat src, bool use_nn_detector, vector<string>& results, vector<vector<Point2f>>& zxing_points) {
|
||||
int width = src.cols;
|
||||
int height = src.rows;
|
||||
if (width <= 20 || height <= 20)
|
||||
return -1; // image data is not enough for providing reliable results
|
||||
|
||||
std::vector<uint8_t> scaled_img_data(src.data, src.data + width * height);
|
||||
zxing::ArrayRef<uint8_t> scaled_img_zx =
|
||||
zxing::ArrayRef<uint8_t>(new zxing::Array<uint8_t>(scaled_img_data));
|
||||
|
||||
vector<zxing::Ref<zxing::Result>> zx_results;
|
||||
|
||||
decode_hints_.setUseNNDetector(use_nn_detector);
|
||||
|
||||
Ref<ImgSource> source;
|
||||
qbarUicomBlock_ = new UnicomBlock(width, height);
|
||||
|
||||
// Four Binarizers
|
||||
int tryBinarizeTime = 4;
|
||||
for (int tb = 0; tb < tryBinarizeTime; tb++) {
|
||||
if (source == NULL || height * width > source->getMaxSize()) {
|
||||
source = ImgSource::create(scaled_img_zx.data(), width, height);
|
||||
} else {
|
||||
source->reset(scaled_img_zx.data(), width, height);
|
||||
}
|
||||
int ret = TryDecode(source, zx_results);
|
||||
if (!ret) {
|
||||
for(size_t k = 0; k < zx_results.size(); k++) {
|
||||
results.emplace_back(zx_results[k]->getText()->getText());
|
||||
vector<Point2f> tmp_qr_points;
|
||||
auto tmp_zx_points = zx_results[k]->getResultPoints();
|
||||
for (int i = 0; i < tmp_zx_points->size() / 4; i++) {
|
||||
const int ind = i * 4;
|
||||
for (int j = 1; j < 4; j++){
|
||||
tmp_qr_points.emplace_back(tmp_zx_points[ind + j]->getX(), tmp_zx_points[ind + j]->getY());
|
||||
}
|
||||
tmp_qr_points.emplace_back(tmp_zx_points[ind]->getX(), tmp_zx_points[ind]->getY());
|
||||
}
|
||||
zxing_points.push_back(tmp_qr_points);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
// try different binarizers
|
||||
binarizer_mgr_.SwitchBinarizer();
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
int DecoderMgr::TryDecode(Ref<LuminanceSource> source, vector<Ref<Result>>& results) {
|
||||
int res = -1;
|
||||
string cell_result;
|
||||
|
||||
// get binarizer
|
||||
zxing::Ref<zxing::Binarizer> binarizer = binarizer_mgr_.Binarize(source);
|
||||
zxing::Ref<zxing::BinaryBitmap> binary_bitmap(new BinaryBitmap(binarizer));
|
||||
binary_bitmap->m_poUnicomBlock = qbarUicomBlock_;
|
||||
|
||||
results = Decode(binary_bitmap, decode_hints_);
|
||||
res = (results.size() == 0) ? 1 : 0;
|
||||
|
||||
if (res == 0) {
|
||||
results[0]->setBinaryMethod(int(binarizer_mgr_.GetCurBinarizer()));
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
vector<Ref<Result>> DecoderMgr::Decode(Ref<BinaryBitmap> image, DecodeHints hints) {
|
||||
return reader_->decode(image, hints);
|
||||
}
|
||||
} // namespace wechat_qrcode
|
||||
} // namespace cv
|
|
@ -0,0 +1,46 @@
|
|||
// This file is part of OpenCV project.
|
||||
// It is subject to the license terms in the LICENSE file found in the top-level directory
|
||||
// of this distribution and at http://opencv.org/license.html.
|
||||
//
|
||||
// Tencent is pleased to support the open source community by making WeChat QRCode available.
|
||||
// Copyright (C) 2020 THL A29 Limited, a Tencent company. All rights reserved.
|
||||
|
||||
#ifndef __OPENCV_WECHAT_QRCODE_DECODERMGR_HPP__
|
||||
#define __OPENCV_WECHAT_QRCODE_DECODERMGR_HPP__
|
||||
|
||||
// zxing
|
||||
#include "zxing/binarizer.hpp"
|
||||
#include "zxing/binarybitmap.hpp"
|
||||
#include "zxing/decodehints.hpp"
|
||||
#include "zxing/qrcode/qrcode_reader.hpp"
|
||||
#include "zxing/result.hpp"
|
||||
|
||||
// qbar
|
||||
#include "binarizermgr.hpp"
|
||||
#include "imgsource.hpp"
|
||||
namespace cv {
|
||||
namespace wechat_qrcode {
|
||||
|
||||
class DecoderMgr {
|
||||
public:
|
||||
DecoderMgr() { reader_ = new zxing::qrcode::QRCodeReader(); };
|
||||
~DecoderMgr(){};
|
||||
|
||||
int decodeImage(cv::Mat src, bool use_nn_detector, vector<string>& result, vector<vector<Point2f>>& zxing_points);
|
||||
|
||||
private:
|
||||
zxing::Ref<zxing::UnicomBlock> qbarUicomBlock_;
|
||||
zxing::DecodeHints decode_hints_;
|
||||
|
||||
zxing::Ref<zxing::qrcode::QRCodeReader> reader_;
|
||||
BinarizerMgr binarizer_mgr_;
|
||||
|
||||
vector<zxing::Ref<zxing::Result>> Decode(zxing::Ref<zxing::BinaryBitmap> image,
|
||||
zxing::DecodeHints hints);
|
||||
|
||||
int TryDecode(zxing::Ref<zxing::LuminanceSource> source, vector<zxing::Ref<zxing::Result>>& result);
|
||||
};
|
||||
|
||||
} // namespace wechat_qrcode
|
||||
} // namespace cv
|
||||
#endif // __OPENCV_WECHAT_QRCODE_DECODERMGR_HPP__
|
|
@ -0,0 +1,66 @@
|
|||
// This file is part of OpenCV project.
|
||||
// It is subject to the license terms in the LICENSE file found in the top-level directory
|
||||
// of this distribution and at http://opencv.org/license.html.
|
||||
//
|
||||
// Tencent is pleased to support the open source community by making WeChat QRCode available.
|
||||
// Copyright (C) 2020 THL A29 Limited, a Tencent company. All rights reserved.
|
||||
#include "../precomp.hpp"
|
||||
#include "align.hpp"
|
||||
|
||||
using std::max;
|
||||
using std::min;
|
||||
namespace cv {
|
||||
namespace wechat_qrcode {
|
||||
Align::Align() { rotate90_ = false; }
|
||||
|
||||
Mat Align::calcWarpMatrix(const Mat src, const Mat dst) {
|
||||
M_ = getPerspectiveTransform(src, dst);
|
||||
M_inv_ = M_.inv();
|
||||
return M_;
|
||||
}
|
||||
|
||||
vector<Point2f> Align::warpBack(const vector<Point2f> &dst_pts) {
|
||||
vector<Point2f> src_pts;
|
||||
for (size_t j = 0; j < dst_pts.size(); j++) {
|
||||
auto src_x = (rotate90_ ? dst_pts[j].y : dst_pts[j].x) + crop_x_;
|
||||
auto src_y = (rotate90_ ? dst_pts[j].x : dst_pts[j].y) + crop_y_;
|
||||
src_pts.push_back(Point2f(src_x, src_y));
|
||||
}
|
||||
return src_pts;
|
||||
}
|
||||
|
||||
Mat Align::crop(const Mat &inputImg, const int width, const int height) {
|
||||
Mat warp_dst = Mat::zeros(height, width, inputImg.type());
|
||||
|
||||
warpPerspective(inputImg, warp_dst, M_, warp_dst.size(), INTER_LINEAR, BORDER_CONSTANT, 255);
|
||||
|
||||
return warp_dst;
|
||||
}
|
||||
|
||||
Mat Align::crop(const Mat &inputImg, const Mat &srcPts, const float paddingW, const float paddingH,
|
||||
const int minPadding) {
|
||||
int x0 = srcPts.at<float>(0, 0);
|
||||
int y0 = srcPts.at<float>(0, 1);
|
||||
int x2 = srcPts.at<float>(2, 0);
|
||||
int y2 = srcPts.at<float>(2, 1);
|
||||
|
||||
int width = x2 - x0 + 1;
|
||||
int height = y2 - y0 + 1;
|
||||
|
||||
int padx = max(paddingW * width, static_cast<float>(minPadding));
|
||||
int pady = max(paddingH * height, static_cast<float>(minPadding));
|
||||
|
||||
crop_x_ = max(x0 - padx, 0);
|
||||
crop_y_ = max(y0 - pady, 0);
|
||||
int end_x = min(x2 + padx, inputImg.cols - 1);
|
||||
int end_y = min(y2 + pady, inputImg.rows - 1);
|
||||
|
||||
Rect crop_roi(crop_x_, crop_y_, end_x - crop_x_ + 1, end_y - crop_y_ + 1);
|
||||
|
||||
Mat dst = inputImg(crop_roi).clone();
|
||||
if (rotate90_) dst = dst.t(); // transpose
|
||||
return dst;
|
||||
}
|
||||
|
||||
} // namespace wechat_qrcode
|
||||
} // namespace cv
|
|
@ -0,0 +1,41 @@
|
|||
// This file is part of OpenCV project.
|
||||
// It is subject to the license terms in the LICENSE file found in the top-level directory
|
||||
// of this distribution and at http://opencv.org/license.html.
|
||||
//
|
||||
// Tencent is pleased to support the open source community by making WeChat QRCode available.
|
||||
// Copyright (C) 2020 THL A29 Limited, a Tencent company. All rights reserved.
|
||||
|
||||
#ifndef __DETECTOR_ALIGN_HPP_
|
||||
#define __DETECTOR_ALIGN_HPP_
|
||||
|
||||
#include <stdio.h>
|
||||
#include <fstream>
|
||||
#include "opencv2/core.hpp"
|
||||
#include "opencv2/imgproc.hpp"
|
||||
|
||||
namespace cv {
|
||||
namespace wechat_qrcode {
|
||||
|
||||
class Align {
|
||||
public:
|
||||
Align();
|
||||
Mat calcWarpMatrix(const Mat src, const Mat dst);
|
||||
std::vector<Point2f> warpBack(const std::vector<Point2f> &dst_pts);
|
||||
Mat crop(const Mat &inputImg, const Mat &srcPts, const float paddingW, const float paddingH,
|
||||
const int minPadding);
|
||||
|
||||
void setRotate90(bool v) { rotate90_ = v; }
|
||||
|
||||
private:
|
||||
Mat crop(const Mat &inputImg, const int width, const int height);
|
||||
Mat M_;
|
||||
Mat M_inv_;
|
||||
|
||||
int crop_x_;
|
||||
int crop_y_;
|
||||
bool rotate90_;
|
||||
};
|
||||
|
||||
} // namespace wechat_qrcode
|
||||
} // namespace cv
|
||||
#endif // __DETECTOR_ALIGN_HPP_
|
|
@ -0,0 +1,57 @@
|
|||
// This file is part of OpenCV project.
|
||||
// It is subject to the license terms in the LICENSE file found in the top-level directory
|
||||
// of this distribution and at http://opencv.org/license.html.
|
||||
//
|
||||
// Tencent is pleased to support the open source community by making WeChat QRCode available.
|
||||
// Copyright (C) 2020 THL A29 Limited, a Tencent company. All rights reserved.
|
||||
#include "../precomp.hpp"
|
||||
#include "ssd_detector.hpp"
|
||||
#define CLIP(x, x1, x2) max(x1, min(x, x2))
|
||||
namespace cv {
|
||||
namespace wechat_qrcode {
|
||||
int SSDDetector::init(const string& proto_path, const string& model_path) {
|
||||
net_ = dnn::readNetFromCaffe(proto_path, model_path);
|
||||
return 0;
|
||||
}
|
||||
|
||||
vector<Mat> SSDDetector::forward(Mat img, const int target_width, const int target_height) {
|
||||
int img_w = img.cols;
|
||||
int img_h = img.rows;
|
||||
Mat input;
|
||||
resize(img, input, Size(target_width, target_height), 0, 0, INTER_CUBIC);
|
||||
|
||||
dnn::blobFromImage(input, input, 1.0 / 255, Size(input.cols, input.rows), {0.0f, 0.0f, 0.0f},
|
||||
false, false);
|
||||
net_.setInput(input, "data");
|
||||
|
||||
auto prob = net_.forward("detection_output");
|
||||
vector<Mat> point_list;
|
||||
// the shape is (1,1,100,7)=>(batch,channel,count,dim)
|
||||
for (int row = 0; row < prob.size[2]; row++) {
|
||||
const float* prob_score = prob.ptr<float>(0, 0, row);
|
||||
// prob_score[0] is not used.
|
||||
// prob_score[1]==1 stands for qrcode
|
||||
if (prob_score[1] == 1 && prob_score[2] > 1E-5) {
|
||||
// add a safe score threshold due to https://github.com/opencv/opencv_contrib/issues/2877
|
||||
// prob_score[2] is the probability of the qrcode, which is not used.
|
||||
auto point = Mat(4, 2, CV_32FC1);
|
||||
float x0 = CLIP(prob_score[3] * img_w, 0.0f, img_w - 1.0f);
|
||||
float y0 = CLIP(prob_score[4] * img_h, 0.0f, img_h - 1.0f);
|
||||
float x1 = CLIP(prob_score[5] * img_w, 0.0f, img_w - 1.0f);
|
||||
float y1 = CLIP(prob_score[6] * img_h, 0.0f, img_h - 1.0f);
|
||||
|
||||
point.at<float>(0, 0) = x0;
|
||||
point.at<float>(0, 1) = y0;
|
||||
point.at<float>(1, 0) = x1;
|
||||
point.at<float>(1, 1) = y0;
|
||||
point.at<float>(2, 0) = x1;
|
||||
point.at<float>(2, 1) = y1;
|
||||
point.at<float>(3, 0) = x0;
|
||||
point.at<float>(3, 1) = y1;
|
||||
point_list.push_back(point);
|
||||
}
|
||||
}
|
||||
return point_list;
|
||||
}
|
||||
} // namespace wechat_qrcode
|
||||
} // namespace cv
|
|
@ -0,0 +1,31 @@
|
|||
// This file is part of OpenCV project.
|
||||
// It is subject to the license terms in the LICENSE file found in the top-level directory
|
||||
// of this distribution and at http://opencv.org/license.html.
|
||||
//
|
||||
// Tencent is pleased to support the open source community by making WeChat QRCode available.
|
||||
// Copyright (C) 2020 THL A29 Limited, a Tencent company. All rights reserved.
|
||||
|
||||
#ifndef __DETECTOR_SSD_DETECTOR_HPP_
|
||||
#define __DETECTOR_SSD_DETECTOR_HPP_
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include "opencv2/dnn.hpp"
|
||||
#include "opencv2/imgproc.hpp"
|
||||
namespace cv {
|
||||
namespace wechat_qrcode {
|
||||
|
||||
class SSDDetector {
|
||||
public:
|
||||
SSDDetector(){};
|
||||
~SSDDetector(){};
|
||||
int init(const std::string& proto_path, const std::string& model_path);
|
||||
std::vector<Mat> forward(Mat img, const int target_width, const int target_height);
|
||||
|
||||
private:
|
||||
dnn::Net net_;
|
||||
};
|
||||
|
||||
} // namespace wechat_qrcode
|
||||
} // namespace cv
|
||||
#endif // __DETECTOR_SSD_DETECTOR_HPP_
|
|
@ -0,0 +1,188 @@
|
|||
// This file is part of OpenCV project.
|
||||
// It is subject to the license terms in the LICENSE file found in the top-level directory
|
||||
// of this distribution and at http://opencv.org/license.html.
|
||||
//
|
||||
// Tencent is pleased to support the open source community by making WeChat QRCode available.
|
||||
// Copyright (C) 2020 THL A29 Limited, a Tencent company. All rights reserved.
|
||||
//
|
||||
// Modified from ZXing. Copyright ZXing authors.
|
||||
// Licensed under the Apache License, Version 2.0 (the "License").
|
||||
#include "precomp.hpp"
|
||||
#include "imgsource.hpp"
|
||||
|
||||
using zxing::ArrayRef;
|
||||
using zxing::ByteMatrix;
|
||||
using zxing::ErrorHandler;
|
||||
using zxing::LuminanceSource;
|
||||
using zxing::Ref;
|
||||
namespace cv {
|
||||
namespace wechat_qrcode {
|
||||
|
||||
// Initialize the ImgSource
|
||||
ImgSource::ImgSource(unsigned char* pixels, int width, int height)
|
||||
: Super(width, height) {
|
||||
luminances = new unsigned char[width * height];
|
||||
memset(luminances, 0, width * height);
|
||||
|
||||
rgbs = pixels;
|
||||
|
||||
dataWidth = width;
|
||||
dataHeight = height;
|
||||
left = 0;
|
||||
top = 0;
|
||||
|
||||
// Make gray luminances first
|
||||
makeGray();
|
||||
}
|
||||
|
||||
// Added for crop function
|
||||
ImgSource::ImgSource(unsigned char* pixels, int width, int height, int left_, int top_,
|
||||
int cropWidth, int cropHeight,
|
||||
ErrorHandler& err_handler)
|
||||
: Super(cropWidth, cropHeight) {
|
||||
rgbs = pixels;
|
||||
|
||||
dataWidth = width;
|
||||
dataHeight = height;
|
||||
left = left_;
|
||||
top = top_;
|
||||
|
||||
// super(width, height);
|
||||
if ((left_ + cropWidth) > dataWidth || (top_ + cropHeight) > dataHeight || top_ < 0 ||
|
||||
left_ < 0) {
|
||||
err_handler =
|
||||
zxing::IllegalArgumentErrorHandler("Crop rectangle does not fit within image data.");
|
||||
return;
|
||||
}
|
||||
|
||||
luminances = new unsigned char[width * height];
|
||||
|
||||
// Make gray luminances first
|
||||
makeGray();
|
||||
}
|
||||
|
||||
ImgSource::~ImgSource() {
|
||||
if (luminances != NULL) {
|
||||
delete[] luminances;
|
||||
}
|
||||
}
|
||||
|
||||
Ref<ImgSource> ImgSource::create(unsigned char* pixels, int width, int height) {
|
||||
return Ref<ImgSource>(new ImgSource(pixels, width, height));
|
||||
}
|
||||
|
||||
Ref<ImgSource> ImgSource::create(unsigned char* pixels, int width, int height, int left, int top,
|
||||
int cropWidth, int cropHeight,
|
||||
zxing::ErrorHandler& err_handler) {
|
||||
return Ref<ImgSource>(new ImgSource(pixels, width, height, left, top, cropWidth, cropHeight, err_handler));
|
||||
}
|
||||
|
||||
void ImgSource::reset(unsigned char* pixels, int width, int height) {
|
||||
rgbs = pixels;
|
||||
left = 0;
|
||||
top = 0;
|
||||
|
||||
setWidth(width);
|
||||
setHeight(height);
|
||||
dataWidth = width;
|
||||
dataHeight = height;
|
||||
makeGrayReset();
|
||||
}
|
||||
|
||||
ArrayRef<char> ImgSource::getRow(int y, zxing::ArrayRef<char> row,
|
||||
zxing::ErrorHandler& err_handler) const {
|
||||
if (y < 0 || y >= getHeight()) {
|
||||
err_handler = zxing::IllegalArgumentErrorHandler("Requested row is outside the image");
|
||||
return ArrayRef<char>();
|
||||
}
|
||||
|
||||
int width = getWidth();
|
||||
if (row->data() == NULL || row->empty() || row->size() < width) {
|
||||
row = zxing::ArrayRef<char>(width);
|
||||
}
|
||||
int offset = (y + top) * dataWidth + left;
|
||||
|
||||
char* rowPtr = &row[0];
|
||||
arrayCopy(luminances, offset, rowPtr, 0, width);
|
||||
|
||||
return row;
|
||||
}
|
||||
|
||||
/** This is a more efficient implementation. */
|
||||
ArrayRef<char> ImgSource::getMatrix() const {
|
||||
int width = getWidth();
|
||||
int height = getHeight();
|
||||
|
||||
int area = width * height;
|
||||
|
||||
// If the caller asks for the entire underlying image, save the copy and
|
||||
// give them the original data. The docs specifically warn that
|
||||
// result.length must be ignored.
|
||||
if (width == dataWidth && height == dataHeight) {
|
||||
return _matrix;
|
||||
}
|
||||
|
||||
zxing::ArrayRef<char> newMatrix = zxing::ArrayRef<char>(area);
|
||||
|
||||
int inputOffset = top * dataWidth + left;
|
||||
|
||||
// If the width matches the full width of the underlying data, perform a
|
||||
// single copy.
|
||||
if (width == dataWidth) {
|
||||
arrayCopy(luminances, inputOffset, &newMatrix[0], 0, area);
|
||||
return newMatrix;
|
||||
}
|
||||
|
||||
// Otherwise copy one cropped row at a time.
|
||||
for (int y = 0; y < height; y++) {
|
||||
int outputOffset = y * width;
|
||||
arrayCopy(luminances, inputOffset, &newMatrix[0], outputOffset, width);
|
||||
inputOffset += dataWidth;
|
||||
}
|
||||
return newMatrix;
|
||||
}
|
||||
|
||||
|
||||
void ImgSource::makeGray() {
|
||||
int area = dataWidth * dataHeight;
|
||||
_matrix = zxing::ArrayRef<char>(area);
|
||||
arrayCopy(rgbs, 0, &_matrix[0], 0, area);
|
||||
}
|
||||
|
||||
void ImgSource::makeGrayReset() {
|
||||
int area = dataWidth * dataHeight;
|
||||
arrayCopy(rgbs, 0, &_matrix[0], 0, area);
|
||||
}
|
||||
|
||||
void ImgSource::arrayCopy(unsigned char* src, int inputOffset, char* dst, int outputOffset,
|
||||
int length) const {
|
||||
const unsigned char* srcPtr = src + inputOffset;
|
||||
char* dstPtr = dst + outputOffset;
|
||||
|
||||
memcpy(dstPtr, srcPtr, length * sizeof(unsigned char));
|
||||
}
|
||||
|
||||
bool ImgSource::isCropSupported() const { return true; }
|
||||
|
||||
Ref<LuminanceSource> ImgSource::crop(int left_, int top_, int width, int height,
|
||||
ErrorHandler& err_handler) const {
|
||||
return ImgSource::create(rgbs, dataWidth, dataHeight, left + left_, top + top_, width, height, err_handler);
|
||||
}
|
||||
|
||||
bool ImgSource::isRotateSupported() const { return false; }
|
||||
|
||||
Ref<LuminanceSource> ImgSource::rotateCounterClockwise(ErrorHandler& err_handler) const {
|
||||
// Intentionally flip the left, top, width, and height arguments as
|
||||
// needed. dataWidth and dataHeight are always kept unrotated.
|
||||
int width = getWidth();
|
||||
int height = getHeight();
|
||||
|
||||
return ImgSource::create(rgbs, dataWidth, dataHeight, top, left, height, width, err_handler);
|
||||
}
|
||||
|
||||
|
||||
Ref<ByteMatrix> ImgSource::getByteMatrix() const {
|
||||
return Ref<ByteMatrix>(new ByteMatrix(getWidth(), getHeight(), getMatrix()));
|
||||
}
|
||||
} // namespace wechat_qrcode
|
||||
} // namespace cv
|
|
@ -0,0 +1,63 @@
|
|||
// This file is part of OpenCV project.
|
||||
// It is subject to the license terms in the LICENSE file found in the top-level directory
|
||||
// of this distribution and at http://opencv.org/license.html.
|
||||
//
|
||||
// Tencent is pleased to support the open source community by making WeChat QRCode available.
|
||||
// Copyright (C) 2020 THL A29 Limited, a Tencent company. All rights reserved.
|
||||
//
|
||||
// Modified from ZXing. Copyright ZXing authors.
|
||||
// Licensed under the Apache License, Version 2.0 (the "License").
|
||||
|
||||
#ifndef __OPENCV_WECHAT_QRCODE_IMGSOURCE_HPP__
|
||||
#define __OPENCV_WECHAT_QRCODE_IMGSOURCE_HPP__
|
||||
#include "zxing/common/bytematrix.hpp"
|
||||
#include "zxing/errorhandler.hpp"
|
||||
#include "zxing/luminance_source.hpp"
|
||||
namespace cv {
|
||||
namespace wechat_qrcode {
|
||||
class ImgSource : public zxing::LuminanceSource {
|
||||
private:
|
||||
typedef LuminanceSource Super;
|
||||
zxing::ArrayRef<char> _matrix;
|
||||
unsigned char* rgbs;
|
||||
unsigned char* luminances;
|
||||
int dataWidth;
|
||||
int dataHeight;
|
||||
int left;
|
||||
int top;
|
||||
void makeGray();
|
||||
void makeGrayReset();
|
||||
|
||||
void arrayCopy(unsigned char* src, int inputOffset, char* dst, int outputOffset,
|
||||
int length) const;
|
||||
|
||||
|
||||
~ImgSource();
|
||||
|
||||
public:
|
||||
ImgSource(unsigned char* pixels, int width, int height);
|
||||
ImgSource(unsigned char* pixels, int width, int height, int left, int top, int cropWidth,
|
||||
int cropHeight, zxing::ErrorHandler& err_handler);
|
||||
|
||||
static zxing::Ref<ImgSource> create(unsigned char* pixels, int width, int height);
|
||||
static zxing::Ref<ImgSource> create(unsigned char* pixels, int width, int height, int left,
|
||||
int top, int cropWidth, int cropHeight, zxing::ErrorHandler& err_handler);
|
||||
void reset(unsigned char* pixels, int width, int height);
|
||||
zxing::ArrayRef<char> getRow(int y, zxing::ArrayRef<char> row,
|
||||
zxing::ErrorHandler& err_handler) const override;
|
||||
zxing::ArrayRef<char> getMatrix() const override;
|
||||
zxing::Ref<zxing::ByteMatrix> getByteMatrix() const override;
|
||||
|
||||
bool isCropSupported() const override;
|
||||
zxing::Ref<LuminanceSource> crop(int left, int top, int width, int height,
|
||||
zxing::ErrorHandler& err_handler) const override;
|
||||
|
||||
bool isRotateSupported() const override;
|
||||
zxing::Ref<LuminanceSource> rotateCounterClockwise(
|
||||
zxing::ErrorHandler& err_handler) const override;
|
||||
|
||||
int getMaxSize() { return dataHeight * dataWidth; }
|
||||
};
|
||||
} // namespace wechat_qrcode
|
||||
} // namespace cv
|
||||
#endif // __OPENCV_WECHAT_QRCODE_IMGSOURCE_HPP__
|
|
@ -0,0 +1,29 @@
|
|||
// This file is part of OpenCV project.
|
||||
// It is subject to the license terms in the LICENSE file found in the top-level directory
|
||||
// of this distribution and at http://opencv.org/license.html.
|
||||
//
|
||||
// Tencent is pleased to support the open source community by making WeChat QRCode available.
|
||||
// Copyright (C) 2020 THL A29 Limited, a Tencent company. All rights reserved.
|
||||
|
||||
#ifndef __OPENCV_WECHAT_QRCODE_PRECOMP_HPP__
|
||||
#define __OPENCV_WECHAT_QRCODE_PRECOMP_HPP__
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning(disable: 4244)
|
||||
#pragma warning(disable: 4267)
|
||||
#endif
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <algorithm>
|
||||
#include <cmath>
|
||||
#include <cstdlib>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <tuple>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
#include <map>
|
||||
#include "imgsource.hpp"
|
||||
using std::ostringstream;
|
||||
using std::string;
|
||||
using std::vector;
|
||||
#endif // __OPENCV_WECHAT_QRCODE_PRECOMP_HPP__
|
|
@ -0,0 +1,63 @@
|
|||
// This file is part of OpenCV project.
|
||||
// It is subject to the license terms in the LICENSE file found in the top-level directory
|
||||
// of this distribution and at http://opencv.org/license.html.
|
||||
//
|
||||
// Tencent is pleased to support the open source community by making WeChat QRCode available.
|
||||
// Copyright (C) 2020 THL A29 Limited, a Tencent company. All rights reserved.
|
||||
#include "../precomp.hpp"
|
||||
#include "super_scale.hpp"
|
||||
|
||||
|
||||
#define CLIP(x, x1, x2) max(x1, min(x, x2))
|
||||
namespace cv {
|
||||
namespace wechat_qrcode {
|
||||
int SuperScale::init(const std::string &proto_path, const std::string &model_path) {
|
||||
srnet_ = dnn::readNetFromCaffe(proto_path, model_path);
|
||||
net_loaded_ = true;
|
||||
return 0;
|
||||
}
|
||||
|
||||
Mat SuperScale::processImageScale(const Mat &src, float scale, const bool &use_sr,
|
||||
int sr_max_size) {
|
||||
Mat dst = src;
|
||||
if (scale == 1.0) { // src
|
||||
return dst;
|
||||
}
|
||||
|
||||
int width = src.cols;
|
||||
int height = src.rows;
|
||||
if (scale == 2.0) { // upsample
|
||||
int SR_TH = sr_max_size;
|
||||
if (use_sr && (int)sqrt(width * height * 1.0) < SR_TH && net_loaded_) {
|
||||
int ret = superResoutionScale(src, dst);
|
||||
if (ret == 0) return dst;
|
||||
}
|
||||
|
||||
{ resize(src, dst, Size(), scale, scale, INTER_CUBIC); }
|
||||
} else if (scale < 1.0) { // downsample
|
||||
resize(src, dst, Size(), scale, scale, INTER_AREA);
|
||||
}
|
||||
|
||||
return dst;
|
||||
}
|
||||
|
||||
int SuperScale::superResoutionScale(const Mat &src, Mat &dst) {
|
||||
Mat blob;
|
||||
dnn::blobFromImage(src, blob, 1.0 / 255, Size(src.cols, src.rows), {0.0f}, false, false);
|
||||
|
||||
srnet_.setInput(blob);
|
||||
auto prob = srnet_.forward();
|
||||
|
||||
dst = Mat(prob.size[2], prob.size[3], CV_8UC1);
|
||||
|
||||
for (int row = 0; row < prob.size[2]; row++) {
|
||||
const float *prob_score = prob.ptr<float>(0, 0, row);
|
||||
for (int col = 0; col < prob.size[3]; col++) {
|
||||
float pixel = prob_score[col] * 255.0;
|
||||
dst.at<uint8_t>(row, col) = static_cast<uint8_t>(CLIP(pixel, 0.0f, 255.0f));
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
} // namespace wechat_qrcode
|
||||
} // namespace cv
|
|
@ -0,0 +1,32 @@
|
|||
// This file is part of OpenCV project.
|
||||
// It is subject to the license terms in the LICENSE file found in the top-level directory
|
||||
// of this distribution and at http://opencv.org/license.html.
|
||||
//
|
||||
// Tencent is pleased to support the open source community by making WeChat QRCode available.
|
||||
// Copyright (C) 2020 THL A29 Limited, a Tencent company. All rights reserved.
|
||||
|
||||
#ifndef __SCALE_SUPER_SCALE_HPP_
|
||||
#define __SCALE_SUPER_SCALE_HPP_
|
||||
|
||||
#include <stdio.h>
|
||||
#include "opencv2/dnn.hpp"
|
||||
#include "opencv2/imgproc.hpp"
|
||||
namespace cv {
|
||||
namespace wechat_qrcode {
|
||||
|
||||
class SuperScale {
|
||||
public:
|
||||
SuperScale(){};
|
||||
~SuperScale(){};
|
||||
int init(const std::string &proto_path, const std::string &model_path);
|
||||
Mat processImageScale(const Mat &src, float scale, const bool &use_sr, int sr_max_size = 160);
|
||||
|
||||
private:
|
||||
dnn::Net srnet_;
|
||||
bool net_loaded_ = false;
|
||||
int superResoutionScale(const cv::Mat &src, cv::Mat &dst);
|
||||
};
|
||||
|
||||
} // namespace wechat_qrcode
|
||||
} // namespace cv
|
||||
#endif // __SCALE_SUPER_SCALE_HPP_
|
|
@ -0,0 +1,247 @@
|
|||
// This file is part of OpenCV project.
|
||||
// It is subject to the license terms in the LICENSE file found in the top-level directory
|
||||
// of this distribution and at http://opencv.org/license.html.
|
||||
//
|
||||
// Tencent is pleased to support the open source community by making WeChat QRCode available.
|
||||
// Copyright (C) 2020 THL A29 Limited, a Tencent company. All rights reserved.
|
||||
#include "precomp.hpp"
|
||||
#include "opencv2/wechat_qrcode.hpp"
|
||||
#include "decodermgr.hpp"
|
||||
#include "detector/align.hpp"
|
||||
#include "detector/ssd_detector.hpp"
|
||||
#include "opencv2/core.hpp"
|
||||
#include "opencv2/core/utils/filesystem.hpp"
|
||||
#include "scale/super_scale.hpp"
|
||||
#include "zxing/result.hpp"
|
||||
namespace cv {
|
||||
namespace wechat_qrcode {
|
||||
class WeChatQRCode::Impl {
|
||||
public:
|
||||
Impl() {}
|
||||
~Impl() {}
|
||||
/**
|
||||
* @brief detect QR codes from the given image
|
||||
*
|
||||
* @param img supports grayscale or color (BGR) image.
|
||||
* @return vector<Mat> detected QR code bounding boxes.
|
||||
*/
|
||||
std::vector<Mat> detect(const Mat& img);
|
||||
/**
|
||||
* @brief decode QR codes from detected points
|
||||
*
|
||||
* @param img supports grayscale or color (BGR) image.
|
||||
* @param candidate_points detected points. we name it "candidate points" which means no
|
||||
* all the qrcode can be decoded.
|
||||
* @param points succussfully decoded qrcode with bounding box points.
|
||||
* @return vector<string>
|
||||
*/
|
||||
std::vector<std::string> decode(const Mat& img, std::vector<Mat>& candidate_points,
|
||||
std::vector<Mat>& points);
|
||||
int applyDetector(const Mat& img, std::vector<Mat>& points);
|
||||
Mat cropObj(const Mat& img, const Mat& point, Align& aligner);
|
||||
std::vector<float> getScaleList(const int width, const int height);
|
||||
std::shared_ptr<SSDDetector> detector_;
|
||||
std::shared_ptr<SuperScale> super_resolution_model_;
|
||||
bool use_nn_detector_, use_nn_sr_;
|
||||
float scaleFactor = -1.f;
|
||||
};
|
||||
|
||||
WeChatQRCode::WeChatQRCode(const String& detector_prototxt_path,
|
||||
const String& detector_caffe_model_path,
|
||||
const String& super_resolution_prototxt_path,
|
||||
const String& super_resolution_caffe_model_path) {
|
||||
p = makePtr<WeChatQRCode::Impl>();
|
||||
if (!detector_caffe_model_path.empty() && !detector_prototxt_path.empty()) {
|
||||
// initialize detector model (caffe)
|
||||
p->use_nn_detector_ = true;
|
||||
CV_Assert(utils::fs::exists(detector_prototxt_path));
|
||||
CV_Assert(utils::fs::exists(detector_caffe_model_path));
|
||||
p->detector_ = make_shared<SSDDetector>();
|
||||
auto ret = p->detector_->init(detector_prototxt_path, detector_caffe_model_path);
|
||||
CV_Assert(ret == 0);
|
||||
} else {
|
||||
p->use_nn_detector_ = false;
|
||||
p->detector_ = NULL;
|
||||
}
|
||||
// initialize super_resolution_model
|
||||
// it could also support non model weights by cubic resizing
|
||||
// so, we initialize it first.
|
||||
p->super_resolution_model_ = make_shared<SuperScale>();
|
||||
if (!super_resolution_prototxt_path.empty() && !super_resolution_caffe_model_path.empty()) {
|
||||
p->use_nn_sr_ = true;
|
||||
// initialize dnn model (caffe format)
|
||||
CV_Assert(utils::fs::exists(super_resolution_prototxt_path));
|
||||
CV_Assert(utils::fs::exists(super_resolution_caffe_model_path));
|
||||
auto ret = p->super_resolution_model_->init(super_resolution_prototxt_path,
|
||||
super_resolution_caffe_model_path);
|
||||
CV_Assert(ret == 0);
|
||||
} else {
|
||||
p->use_nn_sr_ = false;
|
||||
}
|
||||
}
|
||||
|
||||
vector<string> WeChatQRCode::detectAndDecode(InputArray img, OutputArrayOfArrays points) {
|
||||
CV_Assert(!img.empty());
|
||||
CV_CheckDepthEQ(img.depth(), CV_8U, "");
|
||||
|
||||
if (img.cols() <= 20 || img.rows() <= 20) {
|
||||
return vector<string>(); // image data is not enough for providing reliable results
|
||||
}
|
||||
Mat input_img;
|
||||
int incn = img.channels();
|
||||
CV_Check(incn, incn == 1 || incn == 3 || incn == 4, "");
|
||||
if (incn == 3 || incn == 4) {
|
||||
cvtColor(img, input_img, COLOR_BGR2GRAY);
|
||||
} else {
|
||||
input_img = img.getMat();
|
||||
}
|
||||
auto candidate_points = p->detect(input_img);
|
||||
auto res_points = vector<Mat>();
|
||||
auto ret = p->decode(input_img, candidate_points, res_points);
|
||||
// opencv type convert
|
||||
vector<Mat> tmp_points;
|
||||
if (points.needed()) {
|
||||
for (size_t i = 0; i < res_points.size(); i++) {
|
||||
Mat tmp_point;
|
||||
tmp_points.push_back(tmp_point);
|
||||
res_points[i].convertTo(((OutputArray)tmp_points[i]), CV_32FC2);
|
||||
}
|
||||
points.createSameSize(tmp_points, CV_32FC2);
|
||||
points.assign(tmp_points);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
void WeChatQRCode::setScaleFactor(float _scaleFactor) {
|
||||
if (_scaleFactor > 0 && _scaleFactor <= 1.f)
|
||||
p->scaleFactor = _scaleFactor;
|
||||
else
|
||||
p->scaleFactor = -1.f;
|
||||
};
|
||||
|
||||
float WeChatQRCode::getScaleFactor() {
|
||||
return p->scaleFactor;
|
||||
};
|
||||
|
||||
vector<string> WeChatQRCode::Impl::decode(const Mat& img, vector<Mat>& candidate_points,
|
||||
vector<Mat>& points) {
|
||||
if (candidate_points.size() == 0) {
|
||||
return vector<string>();
|
||||
}
|
||||
vector<string> decode_results;
|
||||
for (auto& point : candidate_points) {
|
||||
Mat cropped_img;
|
||||
Align aligner;
|
||||
if (use_nn_detector_) {
|
||||
cropped_img = cropObj(img, point, aligner);
|
||||
} else {
|
||||
cropped_img = img;
|
||||
}
|
||||
// scale_list contains different scale ratios
|
||||
auto scale_list = getScaleList(cropped_img.cols, cropped_img.rows);
|
||||
for (auto cur_scale : scale_list) {
|
||||
Mat scaled_img =
|
||||
super_resolution_model_->processImageScale(cropped_img, cur_scale, use_nn_sr_);
|
||||
string result;
|
||||
DecoderMgr decodemgr;
|
||||
vector<vector<Point2f>> zxing_points, check_points;
|
||||
auto ret = decodemgr.decodeImage(scaled_img, use_nn_detector_, decode_results, zxing_points);
|
||||
if (ret == 0) {
|
||||
for(size_t i = 0; i <zxing_points.size(); i++){
|
||||
vector<Point2f> points_qr = zxing_points[i];
|
||||
for (auto&& pt: points_qr) {
|
||||
pt /= cur_scale;
|
||||
}
|
||||
|
||||
if (use_nn_detector_)
|
||||
points_qr = aligner.warpBack(points_qr);
|
||||
for (int j = 0; j < 4; ++j) {
|
||||
point.at<float>(j, 0) = points_qr[j].x;
|
||||
point.at<float>(j, 1) = points_qr[j].y;
|
||||
}
|
||||
// try to find duplicate qr corners
|
||||
bool isDuplicate = false;
|
||||
for (const auto &tmp_points: check_points) {
|
||||
const float eps = 10.f;
|
||||
for (size_t j = 0; j < tmp_points.size(); j++) {
|
||||
if (abs(tmp_points[j].x - points_qr[j].x) < eps &&
|
||||
abs(tmp_points[j].y - points_qr[j].y) < eps) {
|
||||
isDuplicate = true;
|
||||
}
|
||||
else {
|
||||
isDuplicate = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (isDuplicate == false) {
|
||||
points.push_back(point);
|
||||
check_points.push_back(points_qr);
|
||||
}
|
||||
else {
|
||||
decode_results.erase(decode_results.begin() + i, decode_results.begin() + i + 1);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return decode_results;
|
||||
}
|
||||
|
||||
vector<Mat> WeChatQRCode::Impl::detect(const Mat& img) {
|
||||
auto points = vector<Mat>();
|
||||
|
||||
if (use_nn_detector_) {
|
||||
// use cnn detector
|
||||
auto ret = applyDetector(img, points);
|
||||
CV_Assert(ret == 0);
|
||||
} else {
|
||||
auto width = img.cols, height = img.rows;
|
||||
// if there is no detector, use the full image as input
|
||||
auto point = Mat(4, 2, CV_32FC1);
|
||||
point.at<float>(0, 0) = 0;
|
||||
point.at<float>(0, 1) = 0;
|
||||
point.at<float>(1, 0) = width - 1;
|
||||
point.at<float>(1, 1) = 0;
|
||||
point.at<float>(2, 0) = width - 1;
|
||||
point.at<float>(2, 1) = height - 1;
|
||||
point.at<float>(3, 0) = 0;
|
||||
point.at<float>(3, 1) = height - 1;
|
||||
points.push_back(point);
|
||||
}
|
||||
return points;
|
||||
}
|
||||
|
||||
int WeChatQRCode::Impl::applyDetector(const Mat& img, vector<Mat>& points) {
|
||||
int img_w = img.cols;
|
||||
int img_h = img.rows;
|
||||
|
||||
const float targetArea = 400.f * 400.f;
|
||||
// hard code input size
|
||||
const float tmpScaleFactor = scaleFactor == -1.f ? min(1.f, sqrt(targetArea / (img_w * img_h))) : scaleFactor;
|
||||
int detect_width = img_w * tmpScaleFactor;
|
||||
int detect_height = img_h * tmpScaleFactor;
|
||||
|
||||
points = detector_->forward(img, detect_width, detect_height);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
Mat WeChatQRCode::Impl::cropObj(const Mat& img, const Mat& point, Align& aligner) {
|
||||
// make some padding to boost the qrcode details recall.
|
||||
float padding_w = 0.1f, padding_h = 0.1f;
|
||||
auto min_padding = 15;
|
||||
auto cropped = aligner.crop(img, point, padding_w, padding_h, min_padding);
|
||||
return cropped;
|
||||
}
|
||||
|
||||
// empirical rules
|
||||
vector<float> WeChatQRCode::Impl::getScaleList(const int width, const int height) {
|
||||
if (width < 320 || height < 320) return {1.0, 2.0, 0.5};
|
||||
if (width < 640 && height < 640) return {1.0, 0.5};
|
||||
return {0.5, 1.0};
|
||||
}
|
||||
} // namespace wechat_qrcode
|
||||
} // namespace cv
|
|
@ -0,0 +1,88 @@
|
|||
// This file is part of OpenCV project.
|
||||
// It is subject to the license terms in the LICENSE file found in the top-level directory
|
||||
// of this distribution and at http://opencv.org/license.html.
|
||||
//
|
||||
// Tencent is pleased to support the open source community by making WeChat QRCode available.
|
||||
// Copyright (C) 2020 THL A29 Limited, a Tencent company. All rights reserved.
|
||||
//
|
||||
// Modified from ZXing. Copyright ZXing authors.
|
||||
// Licensed under the Apache License, Version 2.0 (the "License").
|
||||
#include "../precomp.hpp"
|
||||
#include "binarizer.hpp"
|
||||
|
||||
namespace zxing {
|
||||
|
||||
Binarizer::Binarizer(Ref<LuminanceSource> source) : source_(source) {
|
||||
dataWidth = source->getWidth();
|
||||
dataHeight = source->getHeight();
|
||||
|
||||
width = dataWidth;
|
||||
height = dataHeight;
|
||||
|
||||
matrix_ = NULL;
|
||||
matrix0_ = NULL;
|
||||
matrixInverted_ = NULL;
|
||||
|
||||
histogramBinarized = false;
|
||||
usingHistogram = false;
|
||||
}
|
||||
|
||||
Binarizer::~Binarizer() {}
|
||||
|
||||
Ref<LuminanceSource> Binarizer::getLuminanceSource() const { return source_; }
|
||||
|
||||
int Binarizer::getWidth() const {
|
||||
return width;
|
||||
}
|
||||
|
||||
int Binarizer::getHeight() const {
|
||||
return height;
|
||||
}
|
||||
|
||||
int Binarizer::rotateCounterClockwise() { return 0; }
|
||||
|
||||
int Binarizer::rotateCounterClockwise45() { return 0; }
|
||||
|
||||
Ref<BitMatrix> Binarizer::getInvertedMatrix(ErrorHandler& err_handler) {
|
||||
if (!matrix_) {
|
||||
return Ref<BitMatrix>();
|
||||
}
|
||||
|
||||
if (matrixInverted_ == NULL) {
|
||||
matrixInverted_ = new BitMatrix(matrix_->getWidth(), matrix_->getHeight(), err_handler);
|
||||
matrixInverted_->copyOf(matrix_, err_handler);
|
||||
matrixInverted_->flipAll();
|
||||
}
|
||||
|
||||
return matrixInverted_;
|
||||
}
|
||||
|
||||
// Return different black matrix according to cacheMode
|
||||
Ref<BitMatrix> Binarizer::getBlackMatrix(ErrorHandler& err_handler) {
|
||||
if (err_handler.ErrCode()) return Ref<BitMatrix>();
|
||||
matrix_ = matrix0_;
|
||||
return matrix_;
|
||||
}
|
||||
|
||||
Ref<BitArray> Binarizer::getBlackRow(int y, Ref<BitArray> row, ErrorHandler& err_handler) {
|
||||
if (!matrix_) {
|
||||
matrix_ = getBlackMatrix(err_handler);
|
||||
if (err_handler.ErrCode()) return Ref<BitArray>();
|
||||
}
|
||||
|
||||
matrix_->getRow(y, row);
|
||||
return row;
|
||||
}
|
||||
|
||||
ArrayRef<BINARIZER_BLOCK> Binarizer::getBlockArray(int size) {
|
||||
ArrayRef<BINARIZER_BLOCK> blocks(new Array<BINARIZER_BLOCK>(size));
|
||||
|
||||
for (int i = 0; i < blocks->size(); i++) {
|
||||
blocks[i].sum = 0;
|
||||
blocks[i].min = 0xFF;
|
||||
blocks[i].max = 0;
|
||||
}
|
||||
|
||||
return blocks;
|
||||
}
|
||||
} // namespace zxing
|
|
@ -0,0 +1,88 @@
|
|||
// This file is part of OpenCV project.
|
||||
// It is subject to the license terms in the LICENSE file found in the top-level directory
|
||||
// of this distribution and at http://opencv.org/license.html.
|
||||
//
|
||||
// Tencent is pleased to support the open source community by making WeChat QRCode available.
|
||||
// Copyright (C) 2020 THL A29 Limited, a Tencent company. All rights reserved.
|
||||
//
|
||||
// Modified from ZXing. Copyright ZXing authors.
|
||||
// Licensed under the Apache License, Version 2.0 (the "License").
|
||||
|
||||
#ifndef __ZXING_BINARIZER_HPP__
|
||||
#define __ZXING_BINARIZER_HPP__
|
||||
|
||||
#include "common/bitarray.hpp"
|
||||
#include "common/bitmatrix.hpp"
|
||||
#include "common/counted.hpp"
|
||||
#include "errorhandler.hpp"
|
||||
#include "luminance_source.hpp"
|
||||
|
||||
#define ONED_ENABLE_LINE_BINARIZER
|
||||
|
||||
namespace zxing {
|
||||
|
||||
// typedef unsigned char uint8_t;
|
||||
|
||||
struct BINARIZER_BLOCK {
|
||||
int sum;
|
||||
int min;
|
||||
int max;
|
||||
int threshold;
|
||||
// int average;
|
||||
};
|
||||
|
||||
#ifdef ONED_ENABLE_LINE_BINARIZER
|
||||
struct DecodeTipInfo {
|
||||
int class_id;
|
||||
};
|
||||
#endif
|
||||
|
||||
class Binarizer : public Counted {
|
||||
private:
|
||||
Ref<LuminanceSource> source_;
|
||||
bool histogramBinarized;
|
||||
bool usingHistogram;
|
||||
|
||||
public:
|
||||
explicit Binarizer(Ref<LuminanceSource> source);
|
||||
virtual ~Binarizer();
|
||||
|
||||
// Added for store binarized result
|
||||
|
||||
int dataWidth;
|
||||
int dataHeight;
|
||||
int width;
|
||||
int height;
|
||||
|
||||
// Store dynamicalli choice of which matrix is currently used
|
||||
Ref<BitMatrix> matrix_;
|
||||
|
||||
// Restore 0 degree result
|
||||
Ref<BitMatrix> matrix0_;
|
||||
|
||||
Ref<BitMatrix> matrixInverted_;
|
||||
|
||||
bool isRotateSupported() const { return false; }
|
||||
|
||||
// rotate counter clockwise 45 & 90 degree from binarized cache
|
||||
int rotateCounterClockwise();
|
||||
int rotateCounterClockwise45();
|
||||
|
||||
virtual Ref<BitMatrix> getBlackMatrix(ErrorHandler& err_handler);
|
||||
virtual Ref<BitMatrix> getInvertedMatrix(ErrorHandler& err_handler);
|
||||
virtual Ref<BitArray> getBlackRow(int y, Ref<BitArray> row, ErrorHandler& err_handler);
|
||||
|
||||
Ref<LuminanceSource> getLuminanceSource() const;
|
||||
// virtual Ref<Binarizer> createBinarizer(Ref<LuminanceSource> source) = 0;
|
||||
virtual Ref<Binarizer> createBinarizer(Ref<LuminanceSource> source) {
|
||||
return Ref<Binarizer>(new Binarizer(source));
|
||||
};
|
||||
|
||||
int getWidth() const;
|
||||
int getHeight() const;
|
||||
|
||||
ArrayRef<BINARIZER_BLOCK> getBlockArray(int size);
|
||||
};
|
||||
|
||||
} // namespace zxing
|
||||
#endif // __ZXING_BINARIZER_HPP__
|
|
@ -0,0 +1,66 @@
|
|||
// This file is part of OpenCV project.
|
||||
// It is subject to the license terms in the LICENSE file found in the top-level directory
|
||||
// of this distribution and at http://opencv.org/license.html.
|
||||
//
|
||||
// Tencent is pleased to support the open source community by making WeChat QRCode available.
|
||||
// Copyright (C) 2020 THL A29 Limited, a Tencent company. All rights reserved.
|
||||
//
|
||||
// Modified from ZXing. Copyright ZXing authors.
|
||||
// Licensed under the Apache License, Version 2.0 (the "License").
|
||||
#include "../precomp.hpp"
|
||||
#include "binarybitmap.hpp"
|
||||
|
||||
using zxing::BinaryBitmap;
|
||||
using zxing::BitArray;
|
||||
using zxing::BitMatrix;
|
||||
using zxing::ErrorHandler;
|
||||
using zxing::LuminanceSource;
|
||||
using zxing::Ref;
|
||||
|
||||
// VC++
|
||||
using zxing::Binarizer;
|
||||
|
||||
BinaryBitmap::BinaryBitmap(Ref<Binarizer> binarizer) : binarizer_(binarizer) {}
|
||||
|
||||
BinaryBitmap::~BinaryBitmap() {}
|
||||
|
||||
Ref<BitArray> BinaryBitmap::getBlackRow(int y, Ref<BitArray> row, ErrorHandler& err_handler) {
|
||||
Ref<BitArray> bitary = binarizer_->getBlackRow(y, row, err_handler);
|
||||
if (err_handler.ErrCode()) return Ref<BitArray>();
|
||||
return bitary;
|
||||
}
|
||||
|
||||
Ref<BitMatrix> BinaryBitmap::getBlackMatrix(ErrorHandler& err_handler) {
|
||||
Ref<BitMatrix> bitmtx = binarizer_->getBlackMatrix(err_handler);
|
||||
if (err_handler.ErrCode()) return Ref<BitMatrix>();
|
||||
return bitmtx;
|
||||
}
|
||||
|
||||
Ref<BitMatrix> BinaryBitmap::getInvertedMatrix(ErrorHandler& err_handler) {
|
||||
Ref<BitMatrix> bitmtx = binarizer_->getInvertedMatrix(err_handler);
|
||||
if (err_handler.ErrCode()) return Ref<BitMatrix>();
|
||||
return bitmtx;
|
||||
}
|
||||
|
||||
int BinaryBitmap::getWidth() const { return binarizer_->getWidth(); }
|
||||
|
||||
int BinaryBitmap::getHeight() const { return binarizer_->getHeight(); }
|
||||
|
||||
Ref<LuminanceSource> BinaryBitmap::getLuminanceSource() const {
|
||||
return binarizer_->getLuminanceSource();
|
||||
}
|
||||
|
||||
bool BinaryBitmap::isCropSupported() const { return getLuminanceSource()->isCropSupported(); }
|
||||
|
||||
Ref<BinaryBitmap> BinaryBitmap::crop(int left, int top, int width, int height,
|
||||
ErrorHandler& err_handler) {
|
||||
return Ref<BinaryBitmap>(new BinaryBitmap(binarizer_->createBinarizer(
|
||||
getLuminanceSource()->crop(left, top, width, height, err_handler))));
|
||||
}
|
||||
|
||||
bool BinaryBitmap::isRotateSupported() const { return binarizer_->isRotateSupported(); }
|
||||
|
||||
Ref<BinaryBitmap> BinaryBitmap::rotateCounterClockwise() {
|
||||
binarizer_->rotateCounterClockwise();
|
||||
return Ref<BinaryBitmap>(new BinaryBitmap(binarizer_));
|
||||
}
|
|
@ -0,0 +1,53 @@
|
|||
// This file is part of OpenCV project.
|
||||
// It is subject to the license terms in the LICENSE file found in the top-level directory
|
||||
// of this distribution and at http://opencv.org/license.html.
|
||||
//
|
||||
// Tencent is pleased to support the open source community by making WeChat QRCode available.
|
||||
// Copyright (C) 2020 THL A29 Limited, a Tencent company. All rights reserved.
|
||||
//
|
||||
// Modified from ZXing. Copyright ZXing authors.
|
||||
// Licensed under the Apache License, Version 2.0 (the "License").
|
||||
|
||||
#ifndef __ZXING_BINARYBITMAP_HPP__
|
||||
#define __ZXING_BINARYBITMAP_HPP__
|
||||
|
||||
#include "binarizer.hpp"
|
||||
#include "common/bitarray.hpp"
|
||||
#include "common/bitmatrix.hpp"
|
||||
#include "common/counted.hpp"
|
||||
#include "common/unicomblock.hpp"
|
||||
#include "errorhandler.hpp"
|
||||
|
||||
namespace zxing {
|
||||
|
||||
class BinaryBitmap : public Counted {
|
||||
private:
|
||||
Ref<Binarizer> binarizer_;
|
||||
|
||||
public:
|
||||
explicit BinaryBitmap(Ref<Binarizer> binarizer);
|
||||
virtual ~BinaryBitmap();
|
||||
|
||||
Ref<BitArray> getBlackRow(int y, Ref<BitArray> row, ErrorHandler& err_handler);
|
||||
Ref<BitMatrix> getBlackMatrix(ErrorHandler& err_handler);
|
||||
Ref<BitMatrix> getInvertedMatrix(ErrorHandler& err_handler);
|
||||
|
||||
Ref<LuminanceSource> getLuminanceSource() const;
|
||||
Ref<UnicomBlock> m_poUnicomBlock;
|
||||
|
||||
int getWidth() const;
|
||||
int getHeight() const;
|
||||
|
||||
bool isRotateSupported() const;
|
||||
Ref<BinaryBitmap> rotateCounterClockwise();
|
||||
|
||||
bool isCropSupported() const;
|
||||
Ref<BinaryBitmap> crop(int left, int top, int width, int height, ErrorHandler& err_handler);
|
||||
|
||||
bool isHistogramBinarized() const;
|
||||
bool ifUseHistogramBinarize() const;
|
||||
};
|
||||
|
||||
} // namespace zxing
|
||||
|
||||
#endif // __ZXING_BINARYBITMAP_HPP__
|
|
@ -0,0 +1,113 @@
|
|||
// This file is part of OpenCV project.
|
||||
// It is subject to the license terms in the LICENSE file found in the top-level directory
|
||||
// of this distribution and at http://opencv.org/license.html.
|
||||
//
|
||||
// Tencent is pleased to support the open source community by making WeChat QRCode available.
|
||||
// Copyright (C) 2020 THL A29 Limited, a Tencent company. All rights reserved.
|
||||
//
|
||||
// Modified from ZXing. Copyright ZXing authors.
|
||||
// Licensed under the Apache License, Version 2.0 (the "License").
|
||||
|
||||
#ifndef __ZXING_COMMON_ARRAY_HPP__
|
||||
#define __ZXING_COMMON_ARRAY_HPP__
|
||||
|
||||
#include "counted.hpp"
|
||||
|
||||
namespace zxing {
|
||||
|
||||
template <typename T>
|
||||
class Array : public Counted {
|
||||
protected:
|
||||
public:
|
||||
std::vector<T> values_;
|
||||
Array() {}
|
||||
explicit Array(int n) : Counted(), values_(n, T()) {}
|
||||
Array(T const *ts, int n) : Counted(), values_(ts, ts + n) {}
|
||||
Array(T const *ts, T const *te) : Counted(), values_(ts, te) {}
|
||||
Array(T v, int n) : Counted(), values_(n, v) {}
|
||||
explicit Array(std::vector<T> &v) : Counted(), values_(v) {}
|
||||
Array(Array<T> &other) : Counted(), values_(other.values_) {}
|
||||
explicit Array(Array<T> *other) : Counted(), values_(other->values_) {}
|
||||
virtual ~Array() {}
|
||||
Array<T> &operator=(const Array<T> &other) {
|
||||
values_ = other.values_;
|
||||
return *this;
|
||||
}
|
||||
Array<T> &operator=(const std::vector<T> &array) {
|
||||
values_ = array;
|
||||
return *this;
|
||||
}
|
||||
T const &operator[](int i) const { return values_[i]; }
|
||||
T &operator[](int i) { return values_[i]; }
|
||||
int size() const { return values_.size(); }
|
||||
bool empty() const { return values_.size() == 0; }
|
||||
std::vector<T> const &values() const { return values_; }
|
||||
std::vector<T> &values() { return values_; }
|
||||
|
||||
T *data() {
|
||||
// return values_.data();
|
||||
return &values_[0];
|
||||
}
|
||||
void append(T value) { values_.push_back(value); }
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
class ArrayRef : public Counted {
|
||||
private:
|
||||
public:
|
||||
Array<T> *array_;
|
||||
ArrayRef() : array_(0) {}
|
||||
explicit ArrayRef(int n) : array_(0) { reset(new Array<T>(n)); }
|
||||
ArrayRef(T *ts, int n) : array_(0) { reset(new Array<T>(ts, n)); }
|
||||
explicit ArrayRef(Array<T> *a) : array_(0) { reset(a); }
|
||||
ArrayRef(const ArrayRef &other) : Counted(), array_(0) { reset(other.array_); }
|
||||
|
||||
~ArrayRef() {
|
||||
if (array_) {
|
||||
array_->release();
|
||||
}
|
||||
array_ = 0;
|
||||
}
|
||||
|
||||
T const &operator[](int i) const { return (*array_)[i]; }
|
||||
|
||||
T &operator[](int i) { return (*array_)[i]; }
|
||||
|
||||
void reset(Array<T> *a) {
|
||||
if (a) {
|
||||
a->retain();
|
||||
}
|
||||
if (array_) {
|
||||
array_->release();
|
||||
}
|
||||
array_ = a;
|
||||
}
|
||||
void reset(const ArrayRef<T> &other) { reset(other.array_); }
|
||||
ArrayRef<T> &operator=(const ArrayRef<T> &other) {
|
||||
reset(other);
|
||||
return *this;
|
||||
}
|
||||
ArrayRef<T> &operator=(Array<T> *a) {
|
||||
reset(a);
|
||||
return *this;
|
||||
}
|
||||
|
||||
Array<T> &operator*() const { return *array_; }
|
||||
|
||||
Array<T> *operator->() const { return array_; }
|
||||
|
||||
operator bool() const { return array_ != 0; }
|
||||
bool operator!() const { return array_ == 0; }
|
||||
|
||||
T *data() { return array_->data(); }
|
||||
|
||||
void clear() {
|
||||
T *ptr = array_->data();
|
||||
memset(ptr, 0, array_->size());
|
||||
}
|
||||
void append(T value) { array_->append(value); }
|
||||
};
|
||||
|
||||
} // namespace zxing
|
||||
|
||||
#endif // __ZXING_COMMON_ARRAY_HPP__
|
|
@ -0,0 +1,99 @@
|
|||
// This file is part of OpenCV project.
|
||||
// It is subject to the license terms in the LICENSE file found in the top-level directory
|
||||
// of this distribution and at http://opencv.org/license.html.
|
||||
//
|
||||
// Tencent is pleased to support the open source community by making WeChat QRCode available.
|
||||
// Copyright (C) 2020 THL A29 Limited, a Tencent company. All rights reserved.
|
||||
#include "../../../precomp.hpp"
|
||||
#include "adaptive_threshold_mean_binarizer.hpp"
|
||||
using zxing::AdaptiveThresholdMeanBinarizer;
|
||||
|
||||
namespace {
|
||||
const int BLOCK_SIZE = 25;
|
||||
const int Bias = 10;
|
||||
} // namespace
|
||||
|
||||
AdaptiveThresholdMeanBinarizer::AdaptiveThresholdMeanBinarizer(Ref<LuminanceSource> source)
|
||||
: GlobalHistogramBinarizer(source) {}
|
||||
|
||||
AdaptiveThresholdMeanBinarizer::~AdaptiveThresholdMeanBinarizer() {}
|
||||
|
||||
Ref<Binarizer> AdaptiveThresholdMeanBinarizer::createBinarizer(Ref<LuminanceSource> source) {
|
||||
return Ref<Binarizer>(new AdaptiveThresholdMeanBinarizer(source));
|
||||
}
|
||||
|
||||
Ref<BitArray> AdaptiveThresholdMeanBinarizer::getBlackRow(int y, Ref<BitArray> row,
|
||||
ErrorHandler& err_handler) {
|
||||
// First call binarize image in child class to get matrix0_ and binCache
|
||||
if (!matrix0_) {
|
||||
binarizeImage(err_handler);
|
||||
if (err_handler.ErrCode()) return Ref<BitArray>();
|
||||
}
|
||||
|
||||
// Call parent getBlackMatrix to get current matrix
|
||||
return Binarizer::getBlackRow(y, row, err_handler);
|
||||
}
|
||||
|
||||
Ref<BitMatrix> AdaptiveThresholdMeanBinarizer::getBlackMatrix(ErrorHandler& err_handler) {
|
||||
// First call binarize image in child class to get matrix0_ and binCache
|
||||
if (!matrix0_) {
|
||||
binarizeImage(err_handler);
|
||||
if (err_handler.ErrCode()) return Ref<BitMatrix>();
|
||||
}
|
||||
return Binarizer::getBlackMatrix(err_handler);
|
||||
}
|
||||
|
||||
int AdaptiveThresholdMeanBinarizer::binarizeImage(ErrorHandler& err_handler) {
|
||||
if (width >= BLOCK_SIZE && height >= BLOCK_SIZE) {
|
||||
LuminanceSource& source = *getLuminanceSource();
|
||||
Ref<BitMatrix> matrix(new BitMatrix(width, height, err_handler));
|
||||
if (err_handler.ErrCode()) return -1;
|
||||
auto src = (unsigned char*)source.getMatrix()->data();
|
||||
auto dst = matrix->getPtr();
|
||||
cv::Mat mDst;
|
||||
mDst = cv::Mat::zeros(cv::Size(width, height), CV_8UC1);
|
||||
TransBufferToMat(src, mDst, width, height);
|
||||
cv::Mat result;
|
||||
int bs = width / 10;
|
||||
bs = bs + bs % 2 - 1;
|
||||
if (!(bs % 2 == 1 && bs > 1)) return -1;
|
||||
cv::adaptiveThreshold(mDst, result, 255, cv::ADAPTIVE_THRESH_GAUSSIAN_C, cv::THRESH_BINARY,
|
||||
bs, Bias);
|
||||
TransMatToBuffer(result, dst, width, height);
|
||||
if (err_handler.ErrCode()) return -1;
|
||||
matrix0_ = matrix;
|
||||
} else {
|
||||
matrix0_ = GlobalHistogramBinarizer::getBlackMatrix(err_handler);
|
||||
if (err_handler.ErrCode()) return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int AdaptiveThresholdMeanBinarizer::TransBufferToMat(unsigned char* pBuffer, cv::Mat& mDst,
|
||||
int nWidth, int nHeight) {
|
||||
for (int j = 0; j < nHeight; ++j) {
|
||||
unsigned char* data = mDst.ptr<unsigned char>(j);
|
||||
unsigned char* pSubBuffer = pBuffer + (nHeight - 1 - j) * nWidth;
|
||||
memcpy(data, pSubBuffer, nWidth);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int AdaptiveThresholdMeanBinarizer::TransMatToBuffer(cv::Mat mSrc, unsigned char* ppBuffer,
|
||||
int& nWidth, int& nHeight) {
|
||||
nWidth = mSrc.cols;
|
||||
// nWidth = ((nWidth + 3) / 4) * 4;
|
||||
nHeight = mSrc.rows;
|
||||
for (int j = 0; j < nHeight; ++j) {
|
||||
unsigned char* pdi = ppBuffer + j * nWidth;
|
||||
for (int z = 0; z < nWidth; ++z) {
|
||||
int nj = nHeight - j - 1;
|
||||
int value = *(uchar*)(mSrc.ptr<uchar>(nj) + z);
|
||||
if (value > 120)
|
||||
pdi[z] = 0;
|
||||
else
|
||||
pdi[z] = 1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,38 @@
|
|||
// This file is part of OpenCV project.
|
||||
// It is subject to the license terms in the LICENSE file found in the top-level directory
|
||||
// of this distribution and at http://opencv.org/license.html.
|
||||
//
|
||||
// Tencent is pleased to support the open source community by making WeChat QRCode available.
|
||||
// Copyright (C) 2020 THL A29 Limited, a Tencent company. All rights reserved.
|
||||
|
||||
#ifndef __ZXING_COMMON_ADAPTIVE_THRESHOLD_MEAN_BINARIZER_HPP__
|
||||
#define __ZXING_COMMON_ADAPTIVE_THRESHOLD_MEAN_BINARIZER_HPP__
|
||||
#include <opencv2/core.hpp>
|
||||
#include <opencv2/imgproc.hpp>
|
||||
#include "../../binarizer.hpp"
|
||||
#include "../../errorhandler.hpp"
|
||||
#include "../bitarray.hpp"
|
||||
#include "../bitmatrix.hpp"
|
||||
#include "../bytematrix.hpp"
|
||||
#include "global_histogram_binarizer.hpp"
|
||||
|
||||
|
||||
namespace zxing {
|
||||
|
||||
class AdaptiveThresholdMeanBinarizer : public GlobalHistogramBinarizer {
|
||||
public:
|
||||
explicit AdaptiveThresholdMeanBinarizer(Ref<LuminanceSource> source);
|
||||
virtual ~AdaptiveThresholdMeanBinarizer();
|
||||
|
||||
virtual Ref<BitMatrix> getBlackMatrix(ErrorHandler& err_handler) override;
|
||||
virtual Ref<BitArray> getBlackRow(int y, Ref<BitArray> row, ErrorHandler& err_handler) override;
|
||||
Ref<Binarizer> createBinarizer(Ref<LuminanceSource> source) override;
|
||||
|
||||
private:
|
||||
int binarizeImage(ErrorHandler& err_handler);
|
||||
int TransBufferToMat(unsigned char* pBuffer, cv::Mat& mDst, int nWidth, int nHeight);
|
||||
int TransMatToBuffer(cv::Mat mSrc, unsigned char* ppBuffer, int& nWidth, int& nHeight);
|
||||
};
|
||||
|
||||
} // namespace zxing
|
||||
#endif // __ZXING_COMMON_ADAPTIVE_THRESHOLD_MEAN_BINARIZER_HPP__
|
|
@ -0,0 +1,285 @@
|
|||
// This file is part of OpenCV project.
|
||||
// It is subject to the license terms in the LICENSE file found in the top-level directory
|
||||
// of this distribution and at http://opencv.org/license.html.
|
||||
//
|
||||
// Tencent is pleased to support the open source community by making WeChat QRCode available.
|
||||
// Copyright (C) 2020 THL A29 Limited, a Tencent company. All rights reserved.
|
||||
//
|
||||
// Modified from ZXing. Copyright ZXing authors.
|
||||
// Licensed under the Apache License, Version 2.0 (the "License").
|
||||
#include "../../../precomp.hpp"
|
||||
#include "fast_window_binarizer.hpp"
|
||||
using zxing::FastWindowBinarizer;
|
||||
|
||||
|
||||
namespace {
|
||||
const int BLOCK_SIZE = 6;
|
||||
// const int BLOCK_SIZE = 8; // not as good as BLOCK_SIZE = 6
|
||||
const float WINDOW_FRACTION = 0.13f;
|
||||
|
||||
static int min(int a, int b) { return a < b ? a : b; }
|
||||
|
||||
static int max(int a, int b) { return a > b ? a : b; }
|
||||
|
||||
} // namespace
|
||||
|
||||
FastWindowBinarizer::FastWindowBinarizer(Ref<LuminanceSource> source)
|
||||
: GlobalHistogramBinarizer(source), matrix_(NULL), cached_row_(NULL) {
|
||||
width = source->getWidth();
|
||||
height = source->getHeight();
|
||||
int aw = width / BLOCK_SIZE;
|
||||
int ah = height / BLOCK_SIZE;
|
||||
|
||||
int ah2 = ah;
|
||||
int ow2 = aw + 1;
|
||||
|
||||
_luminancesInt = new int[width * height];
|
||||
_blockTotals = new int[ah * aw];
|
||||
_totals = new int[(ah + 1) * (aw + 1)];
|
||||
_rowTotals = new int[ah2 * ow2];
|
||||
|
||||
_internal = new unsigned int[(height + 1) * (width + 1)];
|
||||
}
|
||||
|
||||
FastWindowBinarizer::~FastWindowBinarizer() {
|
||||
delete[] _totals;
|
||||
delete[] _blockTotals;
|
||||
delete[] _luminancesInt;
|
||||
delete[] _rowTotals;
|
||||
|
||||
delete[] _internal;
|
||||
}
|
||||
|
||||
Ref<Binarizer> FastWindowBinarizer::createBinarizer(Ref<LuminanceSource> source) {
|
||||
return Ref<Binarizer>(new FastWindowBinarizer(source));
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates the final BitMatrix once for all requests. This could be called
|
||||
* once from the constructor instead, but there are some advantages to doing it
|
||||
* lazily, such as making profiling easier, and not doing heavy lifting when
|
||||
* callers don't expect it.
|
||||
*/
|
||||
Ref<BitMatrix> FastWindowBinarizer::getBlackMatrix(ErrorHandler& err_handler) {
|
||||
if (!matrix0_) {
|
||||
binarizeImage1(err_handler);
|
||||
if (err_handler.ErrCode()) return Ref<BitMatrix>();
|
||||
}
|
||||
|
||||
return Binarizer::getBlackMatrix(err_handler);
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculate black row from BitMatrix
|
||||
* If BitMatrix has been calculated then just get the row
|
||||
* If BitMatrix has not been calculated then call getBlackMatrix first
|
||||
*/
|
||||
|
||||
Ref<BitArray> FastWindowBinarizer::getBlackRow(int y, Ref<BitArray> row,
|
||||
ErrorHandler& err_handler) {
|
||||
if (!matrix0_) {
|
||||
binarizeImage1(err_handler);
|
||||
if (err_handler.ErrCode()) return Ref<BitArray>();
|
||||
}
|
||||
// Call parent getBlackMatrix to get current matrix
|
||||
return Binarizer::getBlackRow(y, row, err_handler);
|
||||
}
|
||||
|
||||
void FastWindowBinarizer::calcBlockTotals(int* luminancesInt, int* output, int aw, int ah) {
|
||||
for (int by = 0; by < ah; by++) {
|
||||
int ey = (by + 1) * BLOCK_SIZE;
|
||||
for (int bx = 0; bx < aw; bx++) {
|
||||
int t = 0;
|
||||
for (int y = by * BLOCK_SIZE; y < ey; y++) {
|
||||
int offset = y * width + bx * BLOCK_SIZE;
|
||||
int ex = offset + BLOCK_SIZE;
|
||||
for (; offset < ex; offset++) {
|
||||
// int v = luminancesInt[offset] & 0xff;
|
||||
t += luminancesInt[offset];
|
||||
}
|
||||
}
|
||||
output[by * aw + bx] = t;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void FastWindowBinarizer::cumulative(int* data, int* output, int _width, int _height) {
|
||||
int ah = _height;
|
||||
int aw = _width;
|
||||
int ow = _width + 1;
|
||||
// int[][] totals = new int[ah + 1][aw + 1];
|
||||
// int* rowTotals = new int[ah*ow];
|
||||
|
||||
for (int y = 0; y < ah; y++) {
|
||||
int* row = _rowTotals + (y * ow);
|
||||
int* rowdata = data + (y * aw);
|
||||
int t = 0;
|
||||
row[0] = t;
|
||||
|
||||
for (int x = 0; x < aw; x++) {
|
||||
t += rowdata[x];
|
||||
row[x + 1] = t;
|
||||
}
|
||||
}
|
||||
|
||||
for (int x = 0; x <= aw; x++) {
|
||||
output[x] = 0; // First row
|
||||
int t = 0;
|
||||
|
||||
for (int y = 0; y < ah; y++) {
|
||||
t += _rowTotals[y * ow + x];
|
||||
output[(y + 1) * ow + x] = t;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void FastWindowBinarizer::fastIntegral(const unsigned char* inputMatrix,
|
||||
unsigned int* outputMatrix) {
|
||||
// memset(outputMatrix,0,sizeof(int)*(height+1)*(width+1));
|
||||
// unsigned int *columnSum = new unsigned int[width]; // sum of each column
|
||||
// calculate integral of the first line
|
||||
outputMatrix[0] = outputMatrix[width + 1] = 0;
|
||||
for (int i = 0; i < width; i++) {
|
||||
// columnSum[i]=inputMatrix[i];
|
||||
outputMatrix[i + 1] = 0;
|
||||
outputMatrix[width + 1 + i + 1] = outputMatrix[width + 1 + i] + inputMatrix[i];
|
||||
}
|
||||
for (int i = 1; i < height; i++) {
|
||||
const unsigned char* psi = inputMatrix + i * width;
|
||||
unsigned int* pdi = outputMatrix + (i + 1) * (width + 1);
|
||||
// first column of each line
|
||||
pdi[0] = 0;
|
||||
pdi[1] = psi[0];
|
||||
int row_sum = psi[0];
|
||||
// other columns
|
||||
for (int j = 1; j < width; j++) {
|
||||
row_sum += psi[j];
|
||||
pdi[j + 1] = pdi[j + 1 - width - 1] + row_sum;
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
int FastWindowBinarizer::binarizeImage1(ErrorHandler& err_handler) {
|
||||
LuminanceSource& source = *getLuminanceSource();
|
||||
Ref<BitMatrix> matrix(new BitMatrix(width, height, err_handler));
|
||||
if (err_handler.ErrCode()) return -1;
|
||||
|
||||
ArrayRef<char> localLuminances = source.getMatrix();
|
||||
|
||||
unsigned char* src = (unsigned char*)localLuminances->data();
|
||||
unsigned char* dst = matrix->getPtr();
|
||||
fastWindow(src, dst, err_handler);
|
||||
if (err_handler.ErrCode()) return -1;
|
||||
|
||||
matrix0_ = matrix;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void FastWindowBinarizer::fastWindow(const unsigned char* src, unsigned char* dst,
|
||||
ErrorHandler& err_handler) {
|
||||
int r = (int)(min(width, height) * WINDOW_FRACTION / BLOCK_SIZE / 2 + 1);
|
||||
const int NEWH_BLOCK_SIZE = BLOCK_SIZE * r;
|
||||
if (height < NEWH_BLOCK_SIZE || width < NEWH_BLOCK_SIZE) {
|
||||
matrix_ = GlobalHistogramBinarizer::getBlackMatrix(err_handler);
|
||||
return;
|
||||
}
|
||||
const unsigned char* _img = src;
|
||||
fastIntegral(_img, _internal);
|
||||
int aw = width / BLOCK_SIZE;
|
||||
int ah = height / BLOCK_SIZE;
|
||||
memset(dst, 0, sizeof(char) * height * width);
|
||||
for (int ai = 0; ai < ah; ai++) {
|
||||
int top = max(0, ((ai - r + 1) * BLOCK_SIZE));
|
||||
int bottom = min(height, (ai + r) * BLOCK_SIZE);
|
||||
unsigned int* pt = _internal + top * (width + 1);
|
||||
unsigned int* pb = _internal + bottom * (width + 1);
|
||||
for (int aj = 0; aj < aw; aj++) {
|
||||
int left = max(0, (aj - r + 1) * BLOCK_SIZE);
|
||||
int right = min(width, (aj + r) * BLOCK_SIZE);
|
||||
unsigned int block = pb[right] + pt[left] - pt[right] - pb[left];
|
||||
int pixels = (bottom - top) * (right - left);
|
||||
int avg = (int)block / pixels;
|
||||
for (int bi = ai * BLOCK_SIZE; bi < height && bi < (ai + 1) * BLOCK_SIZE; bi++) {
|
||||
const unsigned char* psi = src + bi * width;
|
||||
unsigned char* pdi = dst + bi * width;
|
||||
for (int bj = aj * BLOCK_SIZE; bj < width && bj < (aj + 1) * BLOCK_SIZE; bj++) {
|
||||
if ((int)psi[bj] < avg)
|
||||
pdi[bj] = 1;
|
||||
else
|
||||
pdi[bj] = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// delete [] _internal;
|
||||
return;
|
||||
}
|
||||
|
||||
int FastWindowBinarizer::binarizeImage0(ErrorHandler& err_handler) {
|
||||
// if (matrix_) {
|
||||
// return matrix_;
|
||||
//}
|
||||
|
||||
LuminanceSource& source = *getLuminanceSource();
|
||||
if (width >= BLOCK_SIZE && height >= BLOCK_SIZE) {
|
||||
int r = (int)(min(width, height) * WINDOW_FRACTION / BLOCK_SIZE / 2 + 1);
|
||||
|
||||
int aw = width / BLOCK_SIZE;
|
||||
int ah = height / BLOCK_SIZE;
|
||||
int ow = aw + 1;
|
||||
|
||||
ArrayRef<char> _luminances = source.getMatrix();
|
||||
|
||||
// Get luminances for int value first
|
||||
for (int i = 0; i < width * height; i++) {
|
||||
_luminancesInt[i] = _luminances[i] & 0xff;
|
||||
}
|
||||
|
||||
calcBlockTotals(_luminancesInt, _blockTotals, aw, ah);
|
||||
|
||||
cumulative(_blockTotals, _totals, aw, ah);
|
||||
|
||||
Ref<BitMatrix> newMatrix(new BitMatrix(width, height, err_handler));
|
||||
if (err_handler.ErrCode()) return -1;
|
||||
unsigned char* newimg = newMatrix->getPtr();
|
||||
for (int by = 0; by < ah; by++) {
|
||||
int top = max(0, by - r + 1);
|
||||
int bottom = min(ah, by + r);
|
||||
|
||||
for (int bx = 0; bx < aw; bx++) {
|
||||
int left = max(0, bx - r + 1);
|
||||
int right = min(aw, bx + r);
|
||||
|
||||
int block = _totals[bottom * ow + right] + _totals[top * ow + left] -
|
||||
_totals[top * ow + right] - _totals[bottom * ow + left];
|
||||
|
||||
int pixels = (bottom - top) * (right - left) * BLOCK_SIZE * BLOCK_SIZE;
|
||||
int avg = block / pixels;
|
||||
|
||||
for (int y = by * BLOCK_SIZE; y < (by + 1) * BLOCK_SIZE; y++) {
|
||||
// int offset = y*width;
|
||||
int* plumint = _luminancesInt + y * width;
|
||||
unsigned char* pn = newimg + y * width;
|
||||
for (int x = bx * BLOCK_SIZE; x < (bx + 1) * BLOCK_SIZE; x++) {
|
||||
// int pixel = luminances[y*width + x] & 0xff;
|
||||
// if(plumint[x] < avg)
|
||||
// newMatrix->set(x, y);
|
||||
if (plumint[x] < avg)
|
||||
pn[x] = 1;
|
||||
else
|
||||
pn[x] = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// delete[] data;
|
||||
matrix_ = newMatrix;
|
||||
} else {
|
||||
// If the image is too small, fall back to the global histogram
|
||||
// approach.
|
||||
matrix_ = GlobalHistogramBinarizer::getBlackMatrix(err_handler);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,56 @@
|
|||
// This file is part of OpenCV project.
|
||||
// It is subject to the license terms in the LICENSE file found in the top-level directory
|
||||
// of this distribution and at http://opencv.org/license.html.
|
||||
//
|
||||
// Tencent is pleased to support the open source community by making WeChat QRCode available.
|
||||
// Copyright (C) 2020 THL A29 Limited, a Tencent company. All rights reserved.
|
||||
//
|
||||
// Modified from ZXing. Copyright ZXing authors.
|
||||
// Licensed under the Apache License, Version 2.0 (the "License").
|
||||
|
||||
#ifndef __ZXING_COMMON_DETECTOR_RESULT_HPP__
|
||||
#define __ZXING_COMMON_DETECTOR_RESULT_HPP__
|
||||
|
||||
#include "../../binarizer.hpp"
|
||||
#include "../../errorhandler.hpp"
|
||||
#include "../bitarray.hpp"
|
||||
#include "../bitmatrix.hpp"
|
||||
#include "global_histogram_binarizer.hpp"
|
||||
|
||||
#include <vector>
|
||||
|
||||
namespace zxing {
|
||||
|
||||
class FastWindowBinarizer : public GlobalHistogramBinarizer {
|
||||
private:
|
||||
Ref<BitMatrix> matrix_;
|
||||
Ref<BitArray> cached_row_;
|
||||
|
||||
int* _luminancesInt;
|
||||
int* _blockTotals;
|
||||
int* _totals;
|
||||
int* _rowTotals;
|
||||
|
||||
unsigned int* _internal;
|
||||
|
||||
public:
|
||||
explicit FastWindowBinarizer(Ref<LuminanceSource> source);
|
||||
virtual ~FastWindowBinarizer();
|
||||
|
||||
virtual Ref<BitMatrix> getBlackMatrix(ErrorHandler& err_handler) override;
|
||||
virtual Ref<BitArray> getBlackRow(int y, Ref<BitArray> row, ErrorHandler& err_handler) override;
|
||||
|
||||
Ref<Binarizer> createBinarizer(Ref<LuminanceSource> source) override;
|
||||
|
||||
private:
|
||||
void calcBlockTotals(int* luminancesInt, int* output, int aw, int ah);
|
||||
void cumulative(int* data, int* output, int _width, int _height);
|
||||
int binarizeImage0(ErrorHandler& err_handler);
|
||||
void fastIntegral(const unsigned char* inputMatrix, unsigned int* outputMatrix);
|
||||
int binarizeImage1(ErrorHandler& err_handler);
|
||||
void fastWindow(const unsigned char* src, unsigned char* dst, ErrorHandler& err_handler);
|
||||
};
|
||||
|
||||
} // namespace zxing
|
||||
|
||||
#endif // __ZXING_COMMON_DETECTOR_RESULT_HPP__
|
|
@ -0,0 +1,308 @@
|
|||
// This file is part of OpenCV project.
|
||||
// It is subject to the license terms in the LICENSE file found in the top-level directory
|
||||
// of this distribution and at http://opencv.org/license.html.
|
||||
//
|
||||
// Tencent is pleased to support the open source community by making WeChat QRCode available.
|
||||
// Copyright (C) 2020 THL A29 Limited, a Tencent company. All rights reserved.
|
||||
//
|
||||
// Modified from ZXing. Copyright ZXing authors.
|
||||
// Licensed under the Apache License, Version 2.0 (the "License").
|
||||
#include "../../../precomp.hpp"
|
||||
#include "global_histogram_binarizer.hpp"
|
||||
using zxing::GlobalHistogramBinarizer;
|
||||
|
||||
namespace {
|
||||
const int LUMINANCE_BITS = 5;
|
||||
const int LUMINANCE_SHIFT = 8 - LUMINANCE_BITS;
|
||||
const int LUMINANCE_BUCKETS = 1 << LUMINANCE_BITS;
|
||||
const ArrayRef<char> EMPTY(0);
|
||||
} // namespace
|
||||
|
||||
GlobalHistogramBinarizer::GlobalHistogramBinarizer(Ref<LuminanceSource> source)
|
||||
: Binarizer(source), luminances(EMPTY), buckets(LUMINANCE_BUCKETS) {
|
||||
filtered = false;
|
||||
}
|
||||
|
||||
GlobalHistogramBinarizer::~GlobalHistogramBinarizer() {}
|
||||
|
||||
void GlobalHistogramBinarizer::initArrays(int luminanceSize) {
|
||||
if (luminances->size() < luminanceSize) {
|
||||
luminances = ArrayRef<char>(luminanceSize);
|
||||
}
|
||||
for (int x = 0; x < LUMINANCE_BUCKETS; x++) {
|
||||
buckets[x] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
// Applies simple sharpening to the row data to improve performance of the 1D
|
||||
// readers.
|
||||
Ref<BitArray> GlobalHistogramBinarizer::getBlackRow(int y, Ref<BitArray> row,
|
||||
ErrorHandler& err_handler) {
|
||||
// First call binarize image in child class to get matrix0_ and binCache
|
||||
if (!matrix0_) {
|
||||
binarizeImage0(err_handler);
|
||||
if (err_handler.ErrCode()) return Ref<BitArray>();
|
||||
}
|
||||
// Call parent getBlackMatrix to get current matrix
|
||||
return Binarizer::getBlackRow(y, row, err_handler);
|
||||
}
|
||||
|
||||
// Does not sharpen the data, as this call is intended to only be used by 2D
|
||||
// readers.
|
||||
Ref<BitMatrix> GlobalHistogramBinarizer::getBlackMatrix(ErrorHandler& err_handler) {
|
||||
binarizeImage0(err_handler);
|
||||
if (err_handler.ErrCode()) return Ref<BitMatrix>();
|
||||
// First call binarize image in child class to get matrix0_ and binCache
|
||||
// Call parent getBlackMatrix to get current matrix
|
||||
return Binarizer::getBlackMatrix(err_handler);
|
||||
}
|
||||
|
||||
using namespace std;
|
||||
|
||||
int GlobalHistogramBinarizer::estimateBlackPoint(ArrayRef<int> const& _buckets,
|
||||
ErrorHandler& err_handler) {
|
||||
// Find tallest peak in histogram
|
||||
int numBuckets = _buckets->size();
|
||||
int maxBucketCount = 0;
|
||||
int firstPeak = 0;
|
||||
int firstPeakSize = 0;
|
||||
for (int x = 0; x < numBuckets; x++) {
|
||||
if (_buckets[x] > firstPeakSize) {
|
||||
firstPeak = x;
|
||||
firstPeakSize = _buckets[x];
|
||||
}
|
||||
if (_buckets[x] > maxBucketCount) {
|
||||
maxBucketCount = _buckets[x];
|
||||
}
|
||||
}
|
||||
|
||||
// Find second-tallest peak -- well, another peak that is tall and not
|
||||
// so close to the first one
|
||||
int secondPeak = 0;
|
||||
int secondPeakScore = 0;
|
||||
for (int x = 0; x < numBuckets; x++) {
|
||||
int distanceToBiggest = x - firstPeak;
|
||||
// Encourage more distant second peaks by multiplying by square of
|
||||
// distance
|
||||
int score = _buckets[x] * distanceToBiggest * distanceToBiggest;
|
||||
if (score > secondPeakScore) {
|
||||
secondPeak = x;
|
||||
secondPeakScore = score;
|
||||
}
|
||||
}
|
||||
// Make sure firstPeak corresponds to the black peak.
|
||||
if (firstPeak > secondPeak) {
|
||||
int temp = firstPeak;
|
||||
firstPeak = secondPeak;
|
||||
secondPeak = temp;
|
||||
}
|
||||
|
||||
// Kind of arbitrary; if the two peaks are very close, then we figure there
|
||||
// is so little dynamic range in the image, that discriminating black and
|
||||
// white is too error-prone. Decoding the image/line is either pointless, or
|
||||
// may in some cases lead to a false positive for 1D formats, which are
|
||||
// relatively lenient. We arbitrarily say "close" is "<= 1/16 of the total
|
||||
// histogram buckets apart" std::cerr << "! " << secondPeak << " " <<
|
||||
// firstPeak << " " << numBuckets << std::endl;
|
||||
if (secondPeak - firstPeak <= numBuckets >> 4) {
|
||||
err_handler = NotFoundErrorHandler("NotFound GlobalHistogramBinarizer");
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Find a valley between them that is low and closer to the white peak
|
||||
int bestValley = secondPeak - 1;
|
||||
int bestValleyScore = -1;
|
||||
for (int x = secondPeak - 1; x > firstPeak; x--) {
|
||||
int fromFirst = x - firstPeak;
|
||||
// Favor a "valley" that is not too close to either peak -- especially
|
||||
// not the black peak -- and that has a low value of course
|
||||
int score = fromFirst * fromFirst * (secondPeak - x) * (maxBucketCount - buckets[x]);
|
||||
if (score > bestValleyScore) {
|
||||
bestValley = x;
|
||||
bestValleyScore = score;
|
||||
}
|
||||
}
|
||||
|
||||
// std::cerr << "bps " << (bestValley << LUMINANCE_SHIFT) << std::endl;
|
||||
return bestValley << LUMINANCE_SHIFT;
|
||||
}
|
||||
|
||||
// codes from sagazhou, only works well on one dataset
|
||||
int GlobalHistogramBinarizer::estimateBlackPoint2(ArrayRef<int> const& _buckets) {
|
||||
int midValue = LUMINANCE_BUCKETS / 2 + 1;
|
||||
// Find tallest and lowest peaks in histogram
|
||||
// const int numBuckets = buckets->size();
|
||||
int maxPointArray[LUMINANCE_BUCKETS] = {0};
|
||||
int maxCrusor = 0;
|
||||
int maxValue = 0, maxIndex = 0;
|
||||
int minPointArray[LUMINANCE_BUCKETS] = {0};
|
||||
int minCrusor = 0;
|
||||
|
||||
for (int i = 2; i < LUMINANCE_BUCKETS - 3; i++) {
|
||||
if (_buckets[i] < _buckets[i + 1] && _buckets[i] < _buckets[i + 2] &&
|
||||
_buckets[i] < _buckets[i - 1] && _buckets[i] < _buckets[i - 2]) {
|
||||
minPointArray[minCrusor++] = i;
|
||||
} else if (_buckets[i] > _buckets[i + 1] && _buckets[i] > _buckets[i + 2] &&
|
||||
_buckets[i] > _buckets[i - 1] && _buckets[i] > _buckets[i - 2]) {
|
||||
maxPointArray[maxCrusor++] = i;
|
||||
if (_buckets[i] > maxValue) {
|
||||
maxValue = _buckets[i];
|
||||
maxIndex = i;
|
||||
}
|
||||
}
|
||||
}
|
||||
bool bSlantBlack = true;
|
||||
// most pixels are black
|
||||
for (int i = 0; i < maxCrusor; ++i) {
|
||||
if (maxPointArray[i] > midValue) {
|
||||
bSlantBlack = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
bool bSlantWhite = true;
|
||||
// most pixels are white
|
||||
for (int i = 0; i < maxCrusor; ++i) {
|
||||
if (maxPointArray[i] < midValue) {
|
||||
bSlantWhite = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (bSlantBlack) {
|
||||
int start = maxIndex + 30;
|
||||
int end = midValue;
|
||||
|
||||
if (minCrusor == 0) // unimodal
|
||||
{
|
||||
return 255;
|
||||
} else {
|
||||
int mostLeftIndex = 0;
|
||||
bool bFind = false;
|
||||
|
||||
for (int i = 0; i < minCrusor; ++i) // wave motion
|
||||
{
|
||||
if (minPointArray[i] > start && minPointArray[i] < end) {
|
||||
mostLeftIndex = minPointArray[i];
|
||||
bFind = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (bFind) {
|
||||
return mostLeftIndex;
|
||||
} else {
|
||||
return 255;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (bSlantWhite) {
|
||||
int start = midValue;
|
||||
int end = maxIndex - 30;
|
||||
|
||||
if (minCrusor == 0) // unimodal
|
||||
{
|
||||
return 0;
|
||||
} else {
|
||||
int mostRightIndex = 0;
|
||||
bool bFind = false;
|
||||
|
||||
for (int i = 0; i < minCrusor; ++i) // wave motion
|
||||
{
|
||||
if (minPointArray[i] > start && minPointArray[i] < end) {
|
||||
mostRightIndex = i;
|
||||
bFind = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (bFind) {
|
||||
return mostRightIndex;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// balanced distribution
|
||||
if (maxIndex < midValue) {
|
||||
// the minest min value
|
||||
if (minCrusor == 0) {
|
||||
return 255; // all black
|
||||
} else {
|
||||
int start = maxIndex + 30;
|
||||
int end = 253;
|
||||
|
||||
for (int i = 0; i < minCrusor; ++i) // wave motion
|
||||
{
|
||||
if (minPointArray[i] > start && minPointArray[i] < end) {
|
||||
return minPointArray[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// maxest min value
|
||||
if (minCrusor == 0) {
|
||||
return 0; // white
|
||||
} else {
|
||||
int start = 0;
|
||||
int end = maxIndex - 30;
|
||||
int mostRightIndex = 0;
|
||||
|
||||
for (int i = 0; i < minCrusor; ++i) // wave motion
|
||||
{
|
||||
if (minPointArray[i] > start && minPointArray[i] < end) {
|
||||
mostRightIndex = minPointArray[i];
|
||||
}
|
||||
}
|
||||
|
||||
return mostRightIndex;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int GlobalHistogramBinarizer::binarizeImage0(ErrorHandler& err_handler) {
|
||||
LuminanceSource& source = *getLuminanceSource();
|
||||
Ref<BitMatrix> matrix(new BitMatrix(width, height, err_handler));
|
||||
if (err_handler.ErrCode()) return -1;
|
||||
// Quickly calculates the histogram by sampling four rows from the image.
|
||||
// This proved to be more robust on the blackbox tests than sampling a
|
||||
// diagonal as we used to do.
|
||||
initArrays(width);
|
||||
ArrayRef<int> localBuckets = buckets;
|
||||
|
||||
for (int y = 1; y < 5; y++) {
|
||||
int row = height * y / 5;
|
||||
ArrayRef<char> localLuminances = source.getRow(row, luminances, err_handler);
|
||||
if (err_handler.ErrCode()) return -1;
|
||||
int right = (width << 2) / 5;
|
||||
for (int x = width / 5; x < right; x++) {
|
||||
int pixel = localLuminances[x] & 0xff;
|
||||
localBuckets[pixel >> LUMINANCE_SHIFT]++;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int blackPoint = estimateBlackPoint(localBuckets, err_handler);
|
||||
if (err_handler.ErrCode()) return -1;
|
||||
|
||||
ArrayRef<char> localLuminances = source.getMatrix();
|
||||
for (int y = 0; y < height; y++) {
|
||||
int offset = y * width;
|
||||
for (int x = 0; x < width; x++) {
|
||||
int pixel = localLuminances[offset + x] & 0xff;
|
||||
if (pixel < blackPoint) {
|
||||
matrix->set(x, y);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
matrix0_ = matrix;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
Ref<Binarizer> GlobalHistogramBinarizer::createBinarizer(Ref<LuminanceSource> source) {
|
||||
return Ref<Binarizer>(new GlobalHistogramBinarizer(source));
|
||||
}
|
|
@ -0,0 +1,55 @@
|
|||
// This file is part of OpenCV project.
|
||||
// It is subject to the license terms in the LICENSE file found in the top-level directory
|
||||
// of this distribution and at http://opencv.org/license.html.
|
||||
//
|
||||
// Tencent is pleased to support the open source community by making WeChat QRCode available.
|
||||
// Copyright (C) 2020 THL A29 Limited, a Tencent company. All rights reserved.
|
||||
//
|
||||
// Modified from ZXing. Copyright ZXing authors.
|
||||
// Licensed under the Apache License, Version 2.0 (the "License").
|
||||
|
||||
#ifndef __ZXING_COMMON_GLOBAL_HISTOGRAM_BINARIZER_HPP__
|
||||
#define __ZXING_COMMON_GLOBAL_HISTOGRAM_BINARIZER_HPP__
|
||||
|
||||
#include "../../binarizer.hpp"
|
||||
#include "../../errorhandler.hpp"
|
||||
#include "../array.hpp"
|
||||
#include "../bitarray.hpp"
|
||||
#include "../bitmatrix.hpp"
|
||||
#include "../bytematrix.hpp"
|
||||
|
||||
using zxing::ArrayRef;
|
||||
using zxing::Binarizer;
|
||||
using zxing::BitArray;
|
||||
using zxing::BitMatrix;
|
||||
using zxing::ByteMatrix;
|
||||
using zxing::ErrorHandler;
|
||||
using zxing::LuminanceSource;
|
||||
using zxing::Ref;
|
||||
|
||||
namespace zxing {
|
||||
|
||||
class GlobalHistogramBinarizer : public Binarizer {
|
||||
protected:
|
||||
ArrayRef<char> luminances;
|
||||
ArrayRef<int> buckets;
|
||||
|
||||
public:
|
||||
explicit GlobalHistogramBinarizer(Ref<LuminanceSource> source);
|
||||
virtual ~GlobalHistogramBinarizer();
|
||||
|
||||
virtual Ref<BitArray> getBlackRow(int y, Ref<BitArray> row, ErrorHandler &err_handler) override;
|
||||
virtual Ref<BitMatrix> getBlackMatrix(ErrorHandler &err_handler) override;
|
||||
int estimateBlackPoint(ArrayRef<int> const &buckets, ErrorHandler &err_handler);
|
||||
int estimateBlackPoint2(ArrayRef<int> const &buckets);
|
||||
Ref<Binarizer> createBinarizer(Ref<LuminanceSource> source) override;
|
||||
|
||||
private:
|
||||
int binarizeImage0(ErrorHandler &err_handler);
|
||||
void initArrays(int luminanceSize);
|
||||
bool filtered;
|
||||
};
|
||||
|
||||
} // namespace zxing
|
||||
|
||||
#endif // __ZXING_COMMON_GLOBAL_HISTOGRAM_BINARIZER_HPP__
|
|
@ -0,0 +1,419 @@
|
|||
// This file is part of OpenCV project.
|
||||
// It is subject to the license terms in the LICENSE file found in the top-level directory
|
||||
// of this distribution and at http://opencv.org/license.html.
|
||||
//
|
||||
// Tencent is pleased to support the open source community by making WeChat QRCode available.
|
||||
// Copyright (C) 2020 THL A29 Limited, a Tencent company. All rights reserved.
|
||||
//
|
||||
// Modified from ZXing. Copyright ZXing authors.
|
||||
// Licensed under the Apache License, Version 2.0 (the "License").
|
||||
#include "../../../precomp.hpp"
|
||||
#include "hybrid_binarizer.hpp"
|
||||
|
||||
using zxing::HybridBinarizer;
|
||||
using zxing::BINARIZER_BLOCK;
|
||||
|
||||
// This class uses 5*5 blocks to compute local luminance, where each block is
|
||||
// 8*8 pixels So this is the smallest dimension in each axis we can accept.
|
||||
namespace {
|
||||
const int BLOCK_SIZE_POWER = 3;
|
||||
const int BLOCK_SIZE = 1 << BLOCK_SIZE_POWER; // ...0100...00
|
||||
const int BLOCK_SIZE_MASK = BLOCK_SIZE - 1; // ...0011...11
|
||||
const int MINIMUM_DIMENSION = BLOCK_SIZE * 5;
|
||||
#ifdef USE_SET_INT
|
||||
const int BITS_PER_BYTE = 8;
|
||||
const int BITS_PER_WORD = BitMatrix::bitsPerWord;
|
||||
#endif
|
||||
} // namespace
|
||||
|
||||
HybridBinarizer::HybridBinarizer(Ref<LuminanceSource> source) : GlobalHistogramBinarizer(source) {
|
||||
int subWidth = width >> BLOCK_SIZE_POWER;
|
||||
if ((width & BLOCK_SIZE_MASK) != 0) {
|
||||
subWidth++;
|
||||
}
|
||||
int subHeight = height >> BLOCK_SIZE_POWER;
|
||||
if ((height & BLOCK_SIZE_MASK) != 0) {
|
||||
subHeight++;
|
||||
}
|
||||
|
||||
grayByte_ = source->getByteMatrix();
|
||||
|
||||
blocks_ = getBlockArray(subWidth * subHeight);
|
||||
|
||||
subWidth_ = subWidth;
|
||||
subHeight_ = subHeight;
|
||||
|
||||
initBlocks();
|
||||
initBlockIntegral();
|
||||
}
|
||||
|
||||
HybridBinarizer::~HybridBinarizer() {
|
||||
}
|
||||
|
||||
Ref<Binarizer> HybridBinarizer::createBinarizer(Ref<LuminanceSource> source) {
|
||||
return Ref<Binarizer>(new GlobalHistogramBinarizer(source));
|
||||
}
|
||||
|
||||
int HybridBinarizer::initBlockIntegral() {
|
||||
blockIntegralWidth = subWidth_ + 1;
|
||||
blockIntegralHeight = subHeight_ + 1;
|
||||
blockIntegral_ = new Array<int>(blockIntegralWidth * blockIntegralHeight);
|
||||
|
||||
int* integral = blockIntegral_->data();
|
||||
|
||||
// unsigned char* therow = grayByte_->getByteRow(0);
|
||||
|
||||
// first row only
|
||||
int rs = 0;
|
||||
|
||||
for (int j = 0; j < blockIntegralWidth; j++) {
|
||||
integral[j] = 0;
|
||||
}
|
||||
|
||||
for (int i = 0; i < blockIntegralHeight; i++) {
|
||||
integral[i * blockIntegralWidth] = 0;
|
||||
}
|
||||
|
||||
// remaining cells are sum above and to the left
|
||||
int offsetBlock = 0;
|
||||
int offsetIntegral = 0;
|
||||
|
||||
for (int i = 0; i < subHeight_; ++i) {
|
||||
// therow = grayByte_->getByteRow(i);
|
||||
offsetBlock = i * subWidth_;
|
||||
offsetIntegral = (i + 1) * blockIntegralWidth;
|
||||
rs = 0;
|
||||
|
||||
for (int j = 0; j < subWidth_; ++j) {
|
||||
rs += blocks_[offsetBlock + j].threshold;
|
||||
integral[offsetIntegral + j + 1] = rs + integral[offsetIntegral - blockIntegralWidth + j + 1];
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates the final BitMatrix once for all requests. This could be called
|
||||
* once from the constructor instead, but there are some advantages to doing it
|
||||
* lazily, such as making profiling easier, and not doing heavy lifting when
|
||||
* callers don't expect it.
|
||||
*/
|
||||
Ref<BitMatrix> HybridBinarizer::getBlackMatrix(ErrorHandler& err_handler) {
|
||||
// First call binarize image in child class to get matrix0_ and binCache
|
||||
if (!matrix0_) {
|
||||
binarizeByBlock(err_handler);
|
||||
if (err_handler.ErrCode()) return Ref<BitMatrix>();
|
||||
}
|
||||
|
||||
// First call binarize image in child class to get matrix0_ and binCache
|
||||
// Call parent getBlackMatrix to get current matrix
|
||||
return Binarizer::getBlackMatrix(err_handler);
|
||||
}
|
||||
|
||||
#if 1
|
||||
/**
|
||||
* Calculate black row from BitMatrix
|
||||
* If BitMatrix has been calculated then just get the row
|
||||
* If BitMatrix has not been calculated then call getBlackMatrix first
|
||||
*/
|
||||
Ref<BitArray> HybridBinarizer::getBlackRow(int y, Ref<BitArray> row, ErrorHandler& err_handler) {
|
||||
// First call binarize image in child class to get matrix0_ and binCache
|
||||
if (!matrix0_) {
|
||||
binarizeByBlock(err_handler);
|
||||
if (err_handler.ErrCode()) return Ref<BitArray>();
|
||||
}
|
||||
|
||||
// Call parent getBlackMatrix to get current matrix
|
||||
return Binarizer::getBlackRow(y, row, err_handler);
|
||||
}
|
||||
#endif
|
||||
|
||||
namespace {
|
||||
inline int cap(int value, int min, int max) {
|
||||
return value < min ? min : value > max ? max : value;
|
||||
}
|
||||
} // namespace
|
||||
|
||||
|
||||
// For each block in the image, calculates the average black point using a 5*5
|
||||
// grid of the blocks around it. Also handles the corner cases (fractional
|
||||
// blocks are computed based on the last pixels in the row/column which are also
|
||||
// used in the previous block.)
|
||||
|
||||
#define THRES_BLOCKSIZE 2
|
||||
|
||||
// No use of level now
|
||||
ArrayRef<int> HybridBinarizer::getBlackPoints() {
|
||||
int blackWidth, blackHeight;
|
||||
|
||||
blackWidth = subWidth_;
|
||||
blackHeight = subHeight_;
|
||||
|
||||
ArrayRef<int> blackPoints(blackWidth * blackHeight);
|
||||
|
||||
int* blackArray = blackPoints->data();
|
||||
|
||||
int offset = 0;
|
||||
for (int i = 0; i < blackHeight; i++) {
|
||||
offset = i * blackWidth;
|
||||
for (int j = 0; j < blackWidth; j++) {
|
||||
blackArray[offset + j] = blocks_[offset + j].threshold;
|
||||
}
|
||||
}
|
||||
|
||||
return blackPoints;
|
||||
}
|
||||
|
||||
// Original code 20140606
|
||||
void HybridBinarizer::calculateThresholdForBlock(Ref<ByteMatrix>& _luminances, int subWidth,
|
||||
int subHeight, int SIZE_POWER,
|
||||
// ArrayRef<int> &blackPoints,
|
||||
Ref<BitMatrix> const& matrix,
|
||||
ErrorHandler& err_handler) {
|
||||
int block_size = 1 << SIZE_POWER;
|
||||
|
||||
int maxYOffset = height - block_size;
|
||||
int maxXOffset = width - block_size;
|
||||
|
||||
int* blockIntegral = blockIntegral_->data();
|
||||
|
||||
int blockArea = ((2 * THRES_BLOCKSIZE + 1) * (2 * THRES_BLOCKSIZE + 1));
|
||||
|
||||
for (int y = 0; y < subHeight; y++) {
|
||||
int yoffset = y << SIZE_POWER;
|
||||
if (yoffset > maxYOffset) {
|
||||
yoffset = maxYOffset;
|
||||
}
|
||||
for (int x = 0; x < subWidth; x++) {
|
||||
int xoffset = x << SIZE_POWER;
|
||||
if (xoffset > maxXOffset) {
|
||||
xoffset = maxXOffset;
|
||||
}
|
||||
int left = cap(x, THRES_BLOCKSIZE, subWidth - THRES_BLOCKSIZE - 1);
|
||||
int top = cap(y, THRES_BLOCKSIZE, subHeight - THRES_BLOCKSIZE - 1);
|
||||
|
||||
int sum = 0;
|
||||
// int sum2 = 0;
|
||||
|
||||
int offset1 = (top - THRES_BLOCKSIZE) * blockIntegralWidth + left - THRES_BLOCKSIZE;
|
||||
int offset2 = (top + THRES_BLOCKSIZE + 1) * blockIntegralWidth + left - THRES_BLOCKSIZE;
|
||||
|
||||
int blocksize = THRES_BLOCKSIZE * 2 + 1;
|
||||
|
||||
sum = blockIntegral[offset1] - blockIntegral[offset1 + blocksize] -
|
||||
blockIntegral[offset2] + blockIntegral[offset2 + blocksize];
|
||||
|
||||
int average = sum / blockArea;
|
||||
thresholdBlock(_luminances, xoffset, yoffset, average, matrix, err_handler);
|
||||
if (err_handler.ErrCode()) return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef USE_SET_INT
|
||||
void HybridBinarizer::thresholdFourBlocks(Ref<ByteMatrix>& luminances, int xoffset, int yoffset,
|
||||
int* thresholds, int stride,
|
||||
Ref<BitMatrix> const& matrix) {
|
||||
int setIntCircle = BITS_PER_WORD / BITS_PER_BYTE;
|
||||
for (int y = 0; y < BLOCK_SIZE; y++) {
|
||||
unsigned char* pTemp = luminances->getByteRow(yoffset + y);
|
||||
pTemp = pTemp + xoffset;
|
||||
unsigned int valueInt = 0;
|
||||
int bitPosition = 0;
|
||||
for (int k = 0; k < setIntCircle; k++) {
|
||||
for (int x = 0; x < BLOCK_SIZE; x++) {
|
||||
int pixel = *pTemp++;
|
||||
if (pixel <= thresholds[k]) {
|
||||
// bitPosition=(3-k)*8+x;
|
||||
valueInt |= (unsigned int)1 << bitPosition;
|
||||
}
|
||||
bitPosition++;
|
||||
}
|
||||
}
|
||||
matrix->setIntOneTime(xoffset, yoffset + y, valueInt);
|
||||
}
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
// Applies a single threshold to a block of pixels
|
||||
void HybridBinarizer::thresholdBlock(Ref<ByteMatrix>& _luminances, int xoffset, int yoffset,
|
||||
int threshold, Ref<BitMatrix> const& matrix,
|
||||
ErrorHandler& err_handler) {
|
||||
int rowBitsSize = matrix->getRowBitsSize();
|
||||
int rowSize = width;
|
||||
|
||||
int rowBitStep = rowBitsSize - BLOCK_SIZE;
|
||||
int rowStep = rowSize - BLOCK_SIZE;
|
||||
|
||||
unsigned char* pTemp = _luminances->getByteRow(yoffset, err_handler);
|
||||
if (err_handler.ErrCode()) return;
|
||||
bool* bpTemp = matrix->getRowBoolPtr(yoffset);
|
||||
|
||||
pTemp += xoffset;
|
||||
bpTemp += xoffset;
|
||||
|
||||
for (int y = 0; y < BLOCK_SIZE; y++) {
|
||||
for (int x = 0; x < BLOCK_SIZE; x++) {
|
||||
// comparison needs to be <= so that black == 0 pixels are black
|
||||
// even if the threshold is 0.
|
||||
*bpTemp++ = (*pTemp++ <= threshold) ? true : false;
|
||||
}
|
||||
|
||||
pTemp += rowBitStep;
|
||||
bpTemp += rowStep;
|
||||
}
|
||||
}
|
||||
|
||||
void HybridBinarizer::thresholdIrregularBlock(Ref<ByteMatrix>& _luminances, int xoffset,
|
||||
int yoffset, int blockWidth, int blockHeight,
|
||||
int threshold, Ref<BitMatrix> const& matrix,
|
||||
ErrorHandler& err_handler) {
|
||||
for (int y = 0; y < blockHeight; y++) {
|
||||
unsigned char* pTemp = _luminances->getByteRow(yoffset + y, err_handler);
|
||||
if (err_handler.ErrCode()) return;
|
||||
pTemp = pTemp + xoffset;
|
||||
for (int x = 0; x < blockWidth; x++) {
|
||||
// comparison needs to be <= so that black == 0 pixels are black
|
||||
// even if the threshold is 0.
|
||||
int pixel = *pTemp++;
|
||||
if (pixel <= threshold) {
|
||||
matrix->set(xoffset + x, yoffset + y);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
inline int getBlackPointFromNeighbors(ArrayRef<BINARIZER_BLOCK> block, int subWidth, int x, int y) {
|
||||
return (block[(y - 1) * subWidth + x].threshold + 2 * block[y * subWidth + x - 1].threshold +
|
||||
block[(y - 1) * subWidth + x - 1].threshold) >>
|
||||
2;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
|
||||
#define MIN_DYNAMIC_RANGE 24
|
||||
|
||||
// Calculates a single black point for each block of pixels and saves it away.
|
||||
int HybridBinarizer::initBlocks() {
|
||||
Ref<ByteMatrix>& _luminances = grayByte_;
|
||||
int subWidth = subWidth_;
|
||||
int subHeight = subHeight_;
|
||||
|
||||
unsigned char* bytes = _luminances->bytes;
|
||||
|
||||
const int minDynamicRange = 24;
|
||||
|
||||
for (int y = 0; y < subHeight; y++) {
|
||||
int yoffset = y << BLOCK_SIZE_POWER;
|
||||
int maxYOffset = height - BLOCK_SIZE;
|
||||
if (yoffset > maxYOffset) yoffset = maxYOffset;
|
||||
for (int x = 0; x < subWidth; x++) {
|
||||
int xoffset = x << BLOCK_SIZE_POWER;
|
||||
int maxXOffset = width - BLOCK_SIZE;
|
||||
if (xoffset > maxXOffset) xoffset = maxXOffset;
|
||||
int sum = 0;
|
||||
int min = 0xFF;
|
||||
int max = 0;
|
||||
for (int yy = 0, offset = yoffset * width + xoffset; yy < BLOCK_SIZE;
|
||||
yy++, offset += width) {
|
||||
for (int xx = 0; xx < BLOCK_SIZE; xx++) {
|
||||
// int pixel = luminances->bytes[offset + xx] & 0xFF;
|
||||
int pixel = bytes[offset + xx];
|
||||
sum += pixel;
|
||||
|
||||
// still looking for good contrast
|
||||
if (pixel < min) {
|
||||
min = pixel;
|
||||
}
|
||||
if (pixel > max) {
|
||||
max = pixel;
|
||||
}
|
||||
}
|
||||
|
||||
// short-circuit min/max tests once dynamic range is met
|
||||
if (max - min > minDynamicRange) {
|
||||
// finish the rest of the rows quickly
|
||||
for (yy++, offset += width; yy < BLOCK_SIZE; yy++, offset += width) {
|
||||
for (int xx = 0; xx < BLOCK_SIZE; xx += 2) {
|
||||
sum += bytes[offset + xx];
|
||||
sum += bytes[offset + xx + 1];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
blocks_[y * subWidth + x].min = min;
|
||||
blocks_[y * subWidth + x].max = max;
|
||||
blocks_[y * subWidth + x].sum = sum;
|
||||
blocks_[y * subWidth + x].threshold =
|
||||
getBlockThreshold(x, y, subWidth, sum, min, max, minDynamicRange, BLOCK_SIZE_POWER);
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int HybridBinarizer::getBlockThreshold(int x, int y, int subWidth, int sum, int min, int max,
|
||||
int minDynamicRange, int SIZE_POWER) {
|
||||
// See
|
||||
// http://groups.google.com/group/zxing/browse_thread/thread/d06efa2c35a7ddc0
|
||||
|
||||
// The default estimate is the average of the values in the block.
|
||||
int average = sum >> (SIZE_POWER * 2);
|
||||
if (max - min <= minDynamicRange) {
|
||||
// If variation within the block is low, assume this is a block withe
|
||||
// only light or only dark pixels. In that case we do not want to use
|
||||
// the average, as it would divide this low contrast area into black and
|
||||
// white pixels, essentially creating data out of noise. The default
|
||||
// assumption is that the block is light/background. Since no estimate
|
||||
// for the level of dark pixels exists locally, use half the min for the
|
||||
// block.
|
||||
average = min >> 1;
|
||||
if (y > 0 && x > 0) {
|
||||
// Correct the "white background" assumption for blocks that have
|
||||
// neighbors by comparing the pixels in this block to the previously
|
||||
// calculated black points. This is based on the fact that dark
|
||||
// barcode symbology is always surrounded by some amout of light
|
||||
// background for which reasonable black point estimates were made.
|
||||
// The bp estimated at the boundaries is used for the interior.
|
||||
int bp = getBlackPointFromNeighbors(blocks_, subWidth, x, y);
|
||||
// The (min<bp) is arbitrary but works better than other heuristics
|
||||
// that were tried.
|
||||
if (min < bp) {
|
||||
average = bp;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// blocks_[y * subWidth + x].average = average;
|
||||
// blocks_[y * subWidth + x].threshold = average;
|
||||
|
||||
return average;
|
||||
}
|
||||
|
||||
|
||||
int HybridBinarizer::binarizeByBlock(ErrorHandler& err_handler) {
|
||||
if (width >= MINIMUM_DIMENSION && height >= MINIMUM_DIMENSION) {
|
||||
Ref<BitMatrix> newMatrix(new BitMatrix(width, height, err_handler));
|
||||
if (err_handler.ErrCode()) return -1;
|
||||
|
||||
calculateThresholdForBlock(grayByte_, subWidth_, subHeight_, BLOCK_SIZE_POWER, newMatrix,
|
||||
err_handler);
|
||||
if (err_handler.ErrCode()) return -1;
|
||||
|
||||
matrix0_ = newMatrix;
|
||||
|
||||
} else {
|
||||
// If the image is too small, fall back to the global histogram
|
||||
// approach.
|
||||
matrix0_ = GlobalHistogramBinarizer::getBlackMatrix(err_handler);
|
||||
if (err_handler.ErrCode()) return 1;
|
||||
}
|
||||
// return matrix0_;
|
||||
return 1;
|
||||
}
|
|
@ -0,0 +1,85 @@
|
|||
// This file is part of OpenCV project.
|
||||
// It is subject to the license terms in the LICENSE file found in the top-level directory
|
||||
// of this distribution and at http://opencv.org/license.html.
|
||||
//
|
||||
// Tencent is pleased to support the open source community by making WeChat QRCode available.
|
||||
// Copyright (C) 2020 THL A29 Limited, a Tencent company. All rights reserved.
|
||||
//
|
||||
// Modified from ZXing. Copyright ZXing authors.
|
||||
// Licensed under the Apache License, Version 2.0 (the "License").
|
||||
|
||||
#ifndef __ZXING_COMMON_HYBRID_BINARIZER_HPP__
|
||||
#define __ZXING_COMMON_HYBRID_BINARIZER_HPP__
|
||||
|
||||
#include "../../binarizer.hpp"
|
||||
#include "../../errorhandler.hpp"
|
||||
#include "../bitarray.hpp"
|
||||
#include "../bitmatrix.hpp"
|
||||
#include "../bytematrix.hpp"
|
||||
#include "global_histogram_binarizer.hpp"
|
||||
|
||||
#include <vector>
|
||||
|
||||
|
||||
namespace zxing {
|
||||
|
||||
class HybridBinarizer : public GlobalHistogramBinarizer {
|
||||
private:
|
||||
Ref<ByteMatrix> grayByte_;
|
||||
// ArrayRef<int> integral_;
|
||||
ArrayRef<int> blockIntegral_;
|
||||
ArrayRef<BINARIZER_BLOCK> blocks_;
|
||||
|
||||
ArrayRef<int> blackPoints_;
|
||||
int level_;
|
||||
|
||||
int subWidth_;
|
||||
int subHeight_;
|
||||
int blockIntegralWidth;
|
||||
int blockIntegralHeight;
|
||||
|
||||
public:
|
||||
explicit HybridBinarizer(Ref<LuminanceSource> source);
|
||||
virtual ~HybridBinarizer();
|
||||
|
||||
virtual Ref<BitMatrix> getBlackMatrix(ErrorHandler& err_handler) override;
|
||||
virtual Ref<BitArray> getBlackRow(int y, Ref<BitArray> row, ErrorHandler& err_handler) override;
|
||||
|
||||
Ref<Binarizer> createBinarizer(Ref<LuminanceSource> source) override;
|
||||
|
||||
private:
|
||||
int initIntegral();
|
||||
int initBlockIntegral();
|
||||
int initBlocks();
|
||||
|
||||
// int calculateBlackPoints();
|
||||
ArrayRef<int> getBlackPoints();
|
||||
int getBlockThreshold(int x, int y, int subWidth, int sum, int min, int max,
|
||||
int minDynamicRange, int SIZE_POWER);
|
||||
|
||||
|
||||
void calculateThresholdForBlock(Ref<ByteMatrix>& luminances, int subWidth, int subHeight,
|
||||
int SIZE_POWER, Ref<BitMatrix> const& matrix,
|
||||
ErrorHandler& err_handler);
|
||||
|
||||
|
||||
void thresholdBlock(Ref<ByteMatrix>& luminances, int xoffset, int yoffset, int threshold,
|
||||
Ref<BitMatrix> const& matrix, ErrorHandler& err_handler);
|
||||
|
||||
void thresholdIrregularBlock(Ref<ByteMatrix>& luminances, int xoffset, int yoffset,
|
||||
int blockWidth, int blockHeight, int threshold,
|
||||
Ref<BitMatrix> const& matrix, ErrorHandler& err_handler);
|
||||
|
||||
#ifdef USE_SET_INT
|
||||
void thresholdFourBlocks(Ref<ByteMatrix>& luminances, int xoffset, int yoffset, int* thresholds,
|
||||
int stride, Ref<BitMatrix> const& matrix);
|
||||
#endif
|
||||
|
||||
// Add for binarize image when call getBlackMatrix
|
||||
// By Skylook
|
||||
int binarizeByBlock(ErrorHandler& err_handler);
|
||||
};
|
||||
|
||||
} // namespace zxing
|
||||
|
||||
#endif // __ZXING_COMMON_HYBRID_BINARIZER_HPP__
|
|
@ -0,0 +1,155 @@
|
|||
// This file is part of OpenCV project.
|
||||
// It is subject to the license terms in the LICENSE file found in the top-level directory
|
||||
// of this distribution and at http://opencv.org/license.html.
|
||||
//
|
||||
// Tencent is pleased to support the open source community by making WeChat QRCode available.
|
||||
// Copyright (C) 2020 THL A29 Limited, a Tencent company. All rights reserved.
|
||||
//
|
||||
// Modified from ZXing. Copyright ZXing authors.
|
||||
// Licensed under the Apache License, Version 2.0 (the "License").
|
||||
#include "../../../precomp.hpp"
|
||||
#include "simple_adaptive_binarizer.hpp"
|
||||
|
||||
using zxing::SimpleAdaptiveBinarizer;
|
||||
|
||||
|
||||
SimpleAdaptiveBinarizer::SimpleAdaptiveBinarizer(Ref<LuminanceSource> source)
|
||||
: GlobalHistogramBinarizer(source) {
|
||||
filtered = false;
|
||||
}
|
||||
|
||||
SimpleAdaptiveBinarizer::~SimpleAdaptiveBinarizer() {}
|
||||
|
||||
// Applies simple sharpening to the row data to improve performance of the 1D
|
||||
// readers.
|
||||
Ref<BitArray> SimpleAdaptiveBinarizer::getBlackRow(int y, Ref<BitArray> row,
|
||||
ErrorHandler &err_handler) {
|
||||
// First call binarize image in child class to get matrix0_ and binCache
|
||||
if (!matrix0_) {
|
||||
binarizeImage0(err_handler);
|
||||
if (err_handler.ErrCode()) return Ref<BitArray>();
|
||||
}
|
||||
// Call parent getBlackMatrix to get current matrix
|
||||
return Binarizer::getBlackRow(y, row, err_handler);
|
||||
}
|
||||
|
||||
// Does not sharpen the data, as this call is intended to only be used by 2D
|
||||
// readers.
|
||||
Ref<BitMatrix> SimpleAdaptiveBinarizer::getBlackMatrix(ErrorHandler &err_handler) {
|
||||
// First call binarize image in child class to get matrix0_ and binCache
|
||||
if (!matrix0_) {
|
||||
binarizeImage0(err_handler);
|
||||
if (err_handler.ErrCode()) return Ref<BitMatrix>();
|
||||
}
|
||||
|
||||
// First call binarize image in child class to get matrix0_ and binCache
|
||||
// Call parent getBlackMatrix to get current matrix
|
||||
return Binarizer::getBlackMatrix(err_handler);
|
||||
}
|
||||
|
||||
using namespace std;
|
||||
|
||||
int SimpleAdaptiveBinarizer::binarizeImage0(ErrorHandler &err_handler) {
|
||||
LuminanceSource &source = *getLuminanceSource();
|
||||
|
||||
Ref<BitMatrix> matrix(new BitMatrix(width, height, err_handler));
|
||||
if (err_handler.ErrCode()) return -1;
|
||||
|
||||
ArrayRef<char> localLuminances = source.getMatrix();
|
||||
|
||||
unsigned char *src = (unsigned char *)localLuminances->data();
|
||||
unsigned char *dst = matrix->getPtr();
|
||||
|
||||
qrBinarize(src, dst);
|
||||
|
||||
matrix0_ = matrix;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*A simplified adaptive thresholder.
|
||||
This compares the current pixel value to the mean value of a (large) window
|
||||
surrounding it.*/
|
||||
int SimpleAdaptiveBinarizer::qrBinarize(const unsigned char *src, unsigned char *dst) {
|
||||
unsigned char *mask = dst;
|
||||
|
||||
if (width > 0 && height > 0) {
|
||||
unsigned *col_sums;
|
||||
int logwindw;
|
||||
int logwindh;
|
||||
int windw;
|
||||
int windh;
|
||||
int y0offs;
|
||||
int y1offs;
|
||||
unsigned g;
|
||||
int x;
|
||||
int y;
|
||||
/*We keep the window size fairly large to ensure it doesn't fit
|
||||
completely inside the center of a finder pattern of a version 1 QR
|
||||
code at full resolution.*/
|
||||
for (logwindw = 4; logwindw < 8 && (1 << logwindw) < ((width + 7) >> 3); logwindw++)
|
||||
;
|
||||
for (logwindh = 4; logwindh < 8 && (1 << logwindh) < ((height + 7) >> 3); logwindh++)
|
||||
;
|
||||
windw = 1 << logwindw;
|
||||
windh = 1 << logwindh;
|
||||
|
||||
int logwinds = (logwindw + logwindh);
|
||||
|
||||
col_sums = (unsigned *)malloc(width * sizeof(*col_sums));
|
||||
/*Initialize sums down each column.*/
|
||||
for (x = 0; x < width; x++) {
|
||||
g = src[x];
|
||||
col_sums[x] = (g << (logwindh - 1)) + g;
|
||||
}
|
||||
for (y = 1; y < (windh >> 1); y++) {
|
||||
y1offs = min(y, height - 1) * width;
|
||||
for (x = 0; x < width; x++) {
|
||||
g = src[y1offs + x];
|
||||
col_sums[x] += g;
|
||||
}
|
||||
}
|
||||
for (y = 0; y < height; y++) {
|
||||
unsigned m;
|
||||
int x0;
|
||||
int x1;
|
||||
/*Initialize the sum over the window.*/
|
||||
m = (col_sums[0] << (logwindw - 1)) + col_sums[0];
|
||||
for (x = 1; x < (windw >> 1); x++) {
|
||||
x1 = min(x, width - 1);
|
||||
m += col_sums[x1];
|
||||
}
|
||||
|
||||
int offset = y * width;
|
||||
|
||||
for (x = 0; x < width; x++) {
|
||||
/*Perform the test against the threshold T = (m/n)-D,
|
||||
where n=windw*windh and D=3.*/
|
||||
g = src[offset + x];
|
||||
mask[offset + x] = ((g + 3) << (logwinds) < m);
|
||||
/*Update the window sum.*/
|
||||
if (x + 1 < width) {
|
||||
x0 = max(0, x - (windw >> 1));
|
||||
x1 = min(x + (windw >> 1), width - 1);
|
||||
m += col_sums[x1] - col_sums[x0];
|
||||
}
|
||||
}
|
||||
/*Update the column sums.*/
|
||||
if (y + 1 < height) {
|
||||
y0offs = max(0, y - (windh >> 1)) * width;
|
||||
y1offs = min(y + (windh >> 1), height - 1) * width;
|
||||
for (x = 0; x < width; x++) {
|
||||
col_sums[x] -= src[y0offs + x];
|
||||
col_sums[x] += src[y1offs + x];
|
||||
}
|
||||
}
|
||||
}
|
||||
free(col_sums);
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
Ref<Binarizer> SimpleAdaptiveBinarizer::createBinarizer(Ref<LuminanceSource> source) {
|
||||
return Ref<Binarizer>(new SimpleAdaptiveBinarizer(source));
|
||||
}
|
|
@ -0,0 +1,40 @@
|
|||
// This file is part of OpenCV project.
|
||||
// It is subject to the license terms in the LICENSE file found in the top-level directory
|
||||
// of this distribution and at http://opencv.org/license.html.
|
||||
//
|
||||
// Tencent is pleased to support the open source community by making WeChat QRCode available.
|
||||
// Copyright (C) 2020 THL A29 Limited, a Tencent company. All rights reserved.
|
||||
//
|
||||
// Modified from ZXing. Copyright ZXing authors.
|
||||
// Licensed under the Apache License, Version 2.0 (the "License").
|
||||
|
||||
#ifndef __ZXING_COMMON_SIMPLEADAPTIVEBINARIZER_HPP__
|
||||
#define __ZXING_COMMON_SIMPLEADAPTIVEBINARIZER_HPP__
|
||||
|
||||
#include "../../binarizer.hpp"
|
||||
#include "../array.hpp"
|
||||
#include "../bitarray.hpp"
|
||||
#include "../bitmatrix.hpp"
|
||||
#include "global_histogram_binarizer.hpp"
|
||||
|
||||
|
||||
namespace zxing {
|
||||
|
||||
class SimpleAdaptiveBinarizer : public GlobalHistogramBinarizer {
|
||||
public:
|
||||
explicit SimpleAdaptiveBinarizer(Ref<LuminanceSource> source);
|
||||
virtual ~SimpleAdaptiveBinarizer();
|
||||
|
||||
virtual Ref<BitArray> getBlackRow(int y, Ref<BitArray> row, ErrorHandler &err_handler) override;
|
||||
virtual Ref<BitMatrix> getBlackMatrix(ErrorHandler &err_handler) override;
|
||||
Ref<Binarizer> createBinarizer(Ref<LuminanceSource> source) override;
|
||||
|
||||
private:
|
||||
int binarizeImage0(ErrorHandler &err_handler);
|
||||
int qrBinarize(const unsigned char *src, unsigned char *dst);
|
||||
bool filtered;
|
||||
};
|
||||
|
||||
} // namespace zxing
|
||||
|
||||
#endif // __ZXING_COMMON_SIMPLEADAPTIVEBINARIZER_HPP__
|
|
@ -0,0 +1,233 @@
|
|||
// This file is part of OpenCV project.
|
||||
// It is subject to the license terms in the LICENSE file found in the top-level directory
|
||||
// of this distribution and at http://opencv.org/license.html.
|
||||
//
|
||||
// Tencent is pleased to support the open source community by making WeChat QRCode available.
|
||||
// Copyright (C) 2020 THL A29 Limited, a Tencent company. All rights reserved.
|
||||
//
|
||||
// Modified from ZXing. Copyright ZXing authors.
|
||||
// Licensed under the Apache License, Version 2.0 (the "License").
|
||||
#include "../../precomp.hpp"
|
||||
#include "bitarray.hpp"
|
||||
|
||||
using zxing::ArrayRef;
|
||||
using zxing::BitArray;
|
||||
using zxing::ErrorHandler;
|
||||
using zxing::Ref;
|
||||
|
||||
BitArray::BitArray(int size_) : size(size_), bits(size_), nextSets(size_), nextUnSets(size_) {}
|
||||
|
||||
void BitArray::setUnchar(int i, unsigned char newBits) { bits[i] = newBits; }
|
||||
|
||||
bool BitArray::isRange(int start, int end, bool value, ErrorHandler &err_handler) {
|
||||
if (end < start) {
|
||||
err_handler = IllegalArgumentErrorHandler("isRange");
|
||||
return false;
|
||||
}
|
||||
if (start < 0 || end >= bits->size()) {
|
||||
err_handler = IllegalArgumentErrorHandler("isRange");
|
||||
return false;
|
||||
}
|
||||
if (end == start) {
|
||||
return true; // empty range matches
|
||||
}
|
||||
|
||||
bool startBool = bits[start] != (unsigned char)0;
|
||||
|
||||
int end2 = start;
|
||||
|
||||
if (startBool) {
|
||||
end2 = getNextUnset(start);
|
||||
} else {
|
||||
end2 = getNextSet(start);
|
||||
}
|
||||
|
||||
if (startBool == value) {
|
||||
if (end2 < end) {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void BitArray::reverse() {
|
||||
bool *rowBits = getRowBoolPtr();
|
||||
bool tempBit;
|
||||
|
||||
for (int i = 0; i < size / 2; i++) {
|
||||
tempBit = rowBits[i];
|
||||
rowBits[i] = rowBits[size - i - 1];
|
||||
rowBits[size - i - 1] = tempBit;
|
||||
}
|
||||
}
|
||||
|
||||
void BitArray::initAllNextSets() {
|
||||
bool *rowBits = getRowBoolPtr();
|
||||
|
||||
int *nextSetArray = nextSets->data();
|
||||
int *nextUnsetArray = nextUnSets->data();
|
||||
|
||||
// Init the last one
|
||||
if (rowBits[size - 1]) {
|
||||
nextSetArray[size - 1] = size - 1;
|
||||
nextUnsetArray[size - 1] = size;
|
||||
} else {
|
||||
nextUnsetArray[size - 1] = size - 1;
|
||||
nextSetArray[size - 1] = size;
|
||||
}
|
||||
|
||||
// do inits
|
||||
for (int i = size - 2; i >= 0; i--) {
|
||||
if (rowBits[i]) {
|
||||
nextSetArray[i] = i;
|
||||
nextUnsetArray[i] = nextUnsetArray[i + 1];
|
||||
} else {
|
||||
nextUnsetArray[i] = i;
|
||||
nextSetArray[i] = nextSetArray[i + 1];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void BitArray::initAllNextSetsFromCounters(std::vector<int> counters) {
|
||||
bool *rowBits = getRowBoolPtr();
|
||||
bool isWhite = rowBits[0];
|
||||
int c = 0;
|
||||
int offset = 0;
|
||||
int count = 0;
|
||||
int prevCount = 0;
|
||||
int currCount = 0;
|
||||
int _size = counters.size();
|
||||
|
||||
int *nextSetArray = nextSets->data();
|
||||
int *nextUnsetArray = nextUnSets->data();
|
||||
|
||||
// int* countersArray = counters.data();
|
||||
int *countersArray = &counters[0];
|
||||
|
||||
while (c < _size) {
|
||||
currCount = countersArray[c];
|
||||
|
||||
count += currCount;
|
||||
|
||||
if (isWhite) {
|
||||
for (int i = 0; i < currCount; i++) {
|
||||
offset = prevCount + i;
|
||||
nextSetArray[offset] = prevCount + i;
|
||||
nextUnsetArray[offset] = count;
|
||||
}
|
||||
} else {
|
||||
for (int i = 0; i < currCount; i++) {
|
||||
offset = prevCount + i;
|
||||
nextSetArray[offset] = count;
|
||||
nextUnsetArray[offset] = prevCount + i;
|
||||
}
|
||||
}
|
||||
|
||||
isWhite = !isWhite;
|
||||
|
||||
prevCount += currCount;
|
||||
|
||||
c++;
|
||||
}
|
||||
}
|
||||
|
||||
int BitArray::getNextSet(int from) {
|
||||
if (from >= size) {
|
||||
return size;
|
||||
}
|
||||
return nextSets[from];
|
||||
}
|
||||
|
||||
int BitArray::getNextUnset(int from) {
|
||||
if (from >= size) {
|
||||
return size;
|
||||
}
|
||||
return nextUnSets[from];
|
||||
}
|
||||
|
||||
BitArray::~BitArray() {}
|
||||
|
||||
int BitArray::getSize() const { return size; }
|
||||
|
||||
void BitArray::clear() {
|
||||
int max = bits->size();
|
||||
for (int i = 0; i < max; i++) {
|
||||
bits[i] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
BitArray::Reverse::Reverse(Ref<BitArray> array_) : array(array_) { array->reverse(); }
|
||||
|
||||
BitArray::Reverse::~Reverse() { array->reverse(); }
|
||||
|
||||
void BitArray::appendBit(bool value) {
|
||||
ArrayRef<unsigned char> newBits(size + 1);
|
||||
for (int i = 0; i < size; i++) {
|
||||
newBits[i] = bits[i];
|
||||
}
|
||||
bits = newBits;
|
||||
if (value) {
|
||||
set(size);
|
||||
}
|
||||
++size;
|
||||
}
|
||||
|
||||
int BitArray::getSizeInBytes() const { return size; }
|
||||
|
||||
// Appends the least-significant bits, from value, in order from
|
||||
// most-significant to least-significant. For example, appending 6 bits
|
||||
// from 0x000001E will append the bits 0, 1, 1, 1, 1, 0 in that order.
|
||||
void BitArray::appendBits(int value, int numBits, ErrorHandler &err_handler) {
|
||||
if (numBits < 0 || numBits > 32) {
|
||||
err_handler = IllegalArgumentErrorHandler("Number of bits must be between 0 and 32");
|
||||
return;
|
||||
}
|
||||
ArrayRef<unsigned char> newBits(size + numBits);
|
||||
for (int i = 0; i < size; i++) newBits[i] = bits[i];
|
||||
bits = newBits;
|
||||
for (int numBitsLeft = numBits; numBitsLeft > 0; numBitsLeft--) {
|
||||
if (((value >> (numBitsLeft - 1)) & 0x01) == 1) {
|
||||
set(size);
|
||||
}
|
||||
++size;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
void BitArray::appendBitArray(const BitArray &array) {
|
||||
ArrayRef<unsigned char> newBits(size + array.getSize());
|
||||
for (int i = 0; i < size; ++i) {
|
||||
newBits[i] = bits[i];
|
||||
}
|
||||
bits = newBits;
|
||||
for (int i = 0; i < array.getSize(); ++i) {
|
||||
if (array.get(i)) {
|
||||
set(size);
|
||||
}
|
||||
++size;
|
||||
}
|
||||
}
|
||||
|
||||
void BitArray::toBytes(int bitOffset, ArrayRef<int> &array, int offset, int numBytes) {
|
||||
for (int i = 0; i < numBytes; i++) {
|
||||
int theByte = 0;
|
||||
if (get(bitOffset)) {
|
||||
theByte = 1;
|
||||
}
|
||||
bitOffset++;
|
||||
array[offset + i] = theByte;
|
||||
}
|
||||
}
|
||||
void BitArray::bitXOR(const BitArray &other, ErrorHandler &err_handler) {
|
||||
if (size != other.size) {
|
||||
err_handler = IllegalArgumentErrorHandler("Sizes don't match");
|
||||
return;
|
||||
}
|
||||
|
||||
for (int i = 0; i < bits->size(); i++) {
|
||||
bits[i] = bits[i] == other.bits[i] ? 0 : 1;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,88 @@
|
|||
// This file is part of OpenCV project.
|
||||
// It is subject to the license terms in the LICENSE file found in the top-level directory
|
||||
// of this distribution and at http://opencv.org/license.html.
|
||||
//
|
||||
// Tencent is pleased to support the open source community by making WeChat QRCode available.
|
||||
// Copyright (C) 2020 THL A29 Limited, a Tencent company. All rights reserved.
|
||||
//
|
||||
// Modified from ZXing. Copyright ZXing authors.
|
||||
// Licensed under the Apache License, Version 2.0 (the "License").
|
||||
|
||||
#ifndef __ZXING_COMMON_BITARRAY_HPP__
|
||||
#define __ZXING_COMMON_BITARRAY_HPP__
|
||||
|
||||
#include "../errorhandler.hpp"
|
||||
#include "../zxing.hpp"
|
||||
#include "array.hpp"
|
||||
#include "counted.hpp"
|
||||
#include <cstring>
|
||||
|
||||
namespace zxing {
|
||||
|
||||
class BitArray : public Counted {
|
||||
private:
|
||||
int size;
|
||||
ArrayRef<unsigned char> bits;
|
||||
ArrayRef<int> nextSets;
|
||||
ArrayRef<int> nextUnSets;
|
||||
// bool nextSetsInited;
|
||||
|
||||
public:
|
||||
explicit BitArray(int size);
|
||||
~BitArray();
|
||||
int getSize() const;
|
||||
|
||||
bool get(int i) const { return bits[i] != 0; }
|
||||
void set(int i) {
|
||||
// bits[i] |= 0xFF;
|
||||
bits[i] = true;
|
||||
}
|
||||
void setOneRow(unsigned char* rowBits, int length) {
|
||||
unsigned char* dst = bits->data();
|
||||
memcpy(dst, rowBits, length);
|
||||
}
|
||||
|
||||
bool* getRowBoolPtr() {
|
||||
// return (bool*)bits.data();
|
||||
return (bool*)bits->data();
|
||||
}
|
||||
|
||||
// Init for next sets and unsets to speed up
|
||||
void initAllNextSets();
|
||||
void initAllNextSetsFromCounters(std::vector<int> counters);
|
||||
|
||||
int getNextSet(int from);
|
||||
int getNextUnset(int from);
|
||||
|
||||
void setUnchar(int i, unsigned char newBist);
|
||||
|
||||
void clear();
|
||||
bool isRange(int start, int end, bool value, ErrorHandler& err_handler);
|
||||
|
||||
void reverse();
|
||||
|
||||
class Reverse {
|
||||
private:
|
||||
Ref<BitArray> array;
|
||||
|
||||
public:
|
||||
explicit Reverse(Ref<BitArray> array);
|
||||
~Reverse();
|
||||
};
|
||||
|
||||
void appendBit(bool value);
|
||||
int getSizeInBytes() const;
|
||||
void appendBits(int value, int numberOfBits, ErrorHandler& err_handler);
|
||||
void appendBitArray(const BitArray& array);
|
||||
void toBytes(int bitOffset, ArrayRef<int>& array, int offset, int numBytes);
|
||||
void bitXOR(const BitArray& other, ErrorHandler& err_handler);
|
||||
|
||||
#ifndef USE_BYTE_FOR_BIT
|
||||
private:
|
||||
static int makeArraySize(int size);
|
||||
#endif
|
||||
};
|
||||
|
||||
} // namespace zxing
|
||||
|
||||
#endif // __ZXING_COMMON_BITARRAY_HPP__
|
|
@ -0,0 +1,397 @@
|
|||
// This file is part of OpenCV project.
|
||||
// It is subject to the license terms in the LICENSE file found in the top-level directory
|
||||
// of this distribution and at http://opencv.org/license.html.
|
||||
//
|
||||
// Tencent is pleased to support the open source community by making WeChat QRCode available.
|
||||
// Copyright (C) 2020 THL A29 Limited, a Tencent company. All rights reserved.
|
||||
//
|
||||
// Modified from ZXing. Copyright ZXing authors.
|
||||
// Licensed under the Apache License, Version 2.0 (the "License").
|
||||
#include "../../precomp.hpp"
|
||||
#include "bitmatrix.hpp"
|
||||
|
||||
using zxing::ArrayRef;
|
||||
using zxing::BitArray;
|
||||
using zxing::BitMatrix;
|
||||
using zxing::ErrorHandler;
|
||||
using zxing::Ref;
|
||||
|
||||
void BitMatrix::init(int _width, int _height, ErrorHandler& err_handler) {
|
||||
if (_width < 1 || _height < 1) {
|
||||
err_handler = IllegalArgumentErrorHandler("Both dimensions must be greater than 0");
|
||||
return;
|
||||
}
|
||||
width = _width;
|
||||
height = _height;
|
||||
this->rowBitsSize = width;
|
||||
bits = ArrayRef<unsigned char>(width * height);
|
||||
rowOffsets = ArrayRef<int>(height);
|
||||
|
||||
// offsetRowSize = new int[height];
|
||||
rowOffsets[0] = 0;
|
||||
for (int i = 1; i < height; i++) {
|
||||
rowOffsets[i] = rowOffsets[i - 1] + width;
|
||||
}
|
||||
|
||||
isInitRowCounters = false;
|
||||
isInitColsCounters = false;
|
||||
}
|
||||
|
||||
void BitMatrix::init(int _width, int _height, unsigned char* bitsPtr, ErrorHandler& err_handler) {
|
||||
init(_width, _height, err_handler);
|
||||
if (err_handler.ErrCode()) return;
|
||||
memcpy(bits->data(), bitsPtr, width * height * sizeof(unsigned char));
|
||||
}
|
||||
|
||||
void BitMatrix::initRowCounters() {
|
||||
if (isInitRowCounters == true) {
|
||||
return;
|
||||
}
|
||||
|
||||
row_counters = vector<COUNTER_TYPE>(width * height, 0);
|
||||
row_counters_offset = vector<COUNTER_TYPE>(width * height, 0);
|
||||
row_point_offset = vector<COUNTER_TYPE>(width * height, 0);
|
||||
row_counter_offset_end = vector<COUNTER_TYPE>(height, 0);
|
||||
|
||||
row_counters_recorded = vector<bool>(height, false);
|
||||
|
||||
isInitRowCounters = true;
|
||||
}
|
||||
void BitMatrix::initColsCounters() {
|
||||
if (isInitColsCounters == true) {
|
||||
return;
|
||||
}
|
||||
|
||||
cols_counters = vector<COUNTER_TYPE>(width * height, 0);
|
||||
cols_counters_offset = vector<COUNTER_TYPE>(width * height, 0);
|
||||
cols_point_offset = vector<COUNTER_TYPE>(width * height, 0);
|
||||
cols_counter_offset_end = vector<COUNTER_TYPE>(width, 0);
|
||||
|
||||
cols_counters_recorded = vector<bool>(width, false);
|
||||
|
||||
isInitColsCounters = true;
|
||||
}
|
||||
|
||||
BitMatrix::BitMatrix(int dimension, ErrorHandler& err_handler) {
|
||||
init(dimension, dimension, err_handler);
|
||||
}
|
||||
|
||||
BitMatrix::BitMatrix(int _width, int _height, ErrorHandler& err_handler) {
|
||||
init(_width, _height, err_handler);
|
||||
}
|
||||
|
||||
BitMatrix::BitMatrix(int _width, int _height, unsigned char* bitsPtr, ErrorHandler& err_handler) {
|
||||
init(_width, _height, bitsPtr, err_handler);
|
||||
}
|
||||
// Copy bitMatrix
|
||||
void BitMatrix::copyOf(Ref<BitMatrix> _bits, ErrorHandler& err_handler) {
|
||||
int _width = _bits->getWidth();
|
||||
int _height = _bits->getHeight();
|
||||
init(_width, _height, err_handler);
|
||||
|
||||
for (int y = 0; y < height; y++) {
|
||||
bool* rowPtr = _bits->getRowBoolPtr(y);
|
||||
setRowBool(y, rowPtr);
|
||||
}
|
||||
}
|
||||
|
||||
void BitMatrix::xxor(Ref<BitMatrix> _bits) {
|
||||
if (width != _bits->getWidth() || height != _bits->getHeight()) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (int y = 0; y < height && y < _bits->getHeight(); ++y) {
|
||||
bool* rowPtrA = _bits->getRowBoolPtr(y);
|
||||
bool* rowPtrB = getRowBoolPtr(y);
|
||||
|
||||
for (int x = 0; x < width && x < _bits->getWidth(); ++x) {
|
||||
rowPtrB[x] = rowPtrB[x] ^ rowPtrA[x];
|
||||
}
|
||||
setRowBool(y, rowPtrB);
|
||||
}
|
||||
}
|
||||
|
||||
BitMatrix::~BitMatrix() {}
|
||||
|
||||
void BitMatrix::flip(int x, int y) {
|
||||
bits[rowOffsets[y] + x] = (bits[rowOffsets[y] + x] == (unsigned char)0);
|
||||
}
|
||||
|
||||
void BitMatrix::flipAll() {
|
||||
bool* matrixBits = (bool*)bits->data();
|
||||
for (int i = 0; i < bits->size(); i++) {
|
||||
matrixBits[i] = !matrixBits[i];
|
||||
}
|
||||
}
|
||||
|
||||
void BitMatrix::flipRegion(int left, int top, int _width, int _height, ErrorHandler& err_handler) {
|
||||
if (top < 0 || left < 0) {
|
||||
err_handler = IllegalArgumentErrorHandler("Left and top must be nonnegative");
|
||||
return;
|
||||
}
|
||||
if (_height < 1 || _width < 1) {
|
||||
err_handler = IllegalArgumentErrorHandler("Height and width must be at least 1");
|
||||
return;
|
||||
}
|
||||
int right = left + _width;
|
||||
int bottom = top + _height;
|
||||
if (bottom > this->height || right > this->width) {
|
||||
err_handler = IllegalArgumentErrorHandler("The region must fit inside the matrix");
|
||||
return;
|
||||
}
|
||||
|
||||
for (int y = top; y < bottom; y++) {
|
||||
for (int x = left; x < right; x++) {
|
||||
bits[rowOffsets[y] + x] ^= 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void BitMatrix::setRegion(int left, int top, int _width, int _height, ErrorHandler& err_handler) {
|
||||
if (top < 0 || left < 0) {
|
||||
err_handler = IllegalArgumentErrorHandler("Left and top must be nonnegative");
|
||||
return;
|
||||
}
|
||||
if (_height < 1 || _width < 1) {
|
||||
err_handler = IllegalArgumentErrorHandler("Height and width must be at least 1");
|
||||
return;
|
||||
}
|
||||
int right = left + _width;
|
||||
int bottom = top + _height;
|
||||
if (bottom > this->height || right > this->width) {
|
||||
err_handler = IllegalArgumentErrorHandler("The region must fit inside the matrix");
|
||||
return;
|
||||
}
|
||||
|
||||
for (int y = top; y < bottom; y++) {
|
||||
for (int x = left; x < right; x++) {
|
||||
bits[rowOffsets[y] + x] = true;
|
||||
// bits[rowOffsets[y]+x] |= 0xFF;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Ref<BitArray> BitMatrix::getRow(int y, Ref<BitArray> row) {
|
||||
if (row.empty() || row->getSize() < width) {
|
||||
row = new BitArray(width);
|
||||
}
|
||||
|
||||
// row->
|
||||
unsigned char* src = bits.data() + rowOffsets[y];
|
||||
row->setOneRow(src, width);
|
||||
|
||||
return row;
|
||||
}
|
||||
|
||||
ArrayRef<int> BitMatrix::getTopLeftOnBit() const {
|
||||
int bitsOffset = 0;
|
||||
while (bitsOffset < bits->size() && bits[bitsOffset] == 0) {
|
||||
bitsOffset++;
|
||||
}
|
||||
if (bitsOffset == bits->size()) {
|
||||
return ArrayRef<int>();
|
||||
}
|
||||
int y = bitsOffset / width;
|
||||
int x = bitsOffset % width;
|
||||
ArrayRef<int> res(2);
|
||||
res[0] = x;
|
||||
res[1] = y;
|
||||
return res;
|
||||
}
|
||||
|
||||
ArrayRef<int> BitMatrix::getBottomRightOnBit() const {
|
||||
int bitsOffset = bits->size() - 1;
|
||||
while (bitsOffset >= 0 && bits[bitsOffset] == 0) {
|
||||
bitsOffset--;
|
||||
}
|
||||
if (bitsOffset < 0) {
|
||||
return ArrayRef<int>();
|
||||
}
|
||||
|
||||
int y = bitsOffset / width;
|
||||
int x = bitsOffset % width;
|
||||
ArrayRef<int> res(2);
|
||||
res[0] = x;
|
||||
res[1] = y;
|
||||
return res;
|
||||
}
|
||||
|
||||
void BitMatrix::getRowBool(int y, bool* getrow) {
|
||||
int offset = rowOffsets[y];
|
||||
unsigned char* src = bits.data() + offset;
|
||||
memcpy(getrow, src, rowBitsSize * sizeof(bool));
|
||||
}
|
||||
|
||||
void BitMatrix::setRowBool(int y, bool* row) {
|
||||
int offset = rowOffsets[y];
|
||||
unsigned char* dst = bits.data() + offset;
|
||||
memcpy(dst, row, rowBitsSize * sizeof(bool));
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
bool* BitMatrix::getRowBoolPtr(int y) {
|
||||
int offset = y * rowBitsSize;
|
||||
unsigned char* src = bits.data() + offset;
|
||||
return (bool*)src;
|
||||
}
|
||||
|
||||
void BitMatrix::clear() {
|
||||
int size = bits->size();
|
||||
|
||||
unsigned char* dst = bits->data();
|
||||
memset(dst, 0, size * sizeof(unsigned char));
|
||||
}
|
||||
|
||||
int BitMatrix::getWidth() const { return width; }
|
||||
|
||||
int BitMatrix::getHeight() const { return height; }
|
||||
|
||||
COUNTER_TYPE* BitMatrix::getRowPointInRecords(int y) {
|
||||
if (!row_point_offset[y]) {
|
||||
setRowRecords(y);
|
||||
}
|
||||
int offset = y * width;
|
||||
COUNTER_TYPE* counters = &row_point_offset[0] + offset;
|
||||
return (COUNTER_TYPE*)counters;
|
||||
}
|
||||
|
||||
COUNTER_TYPE* BitMatrix::getRowRecords(int y) {
|
||||
if (!row_counters_recorded[y]) {
|
||||
setRowRecords(y);
|
||||
}
|
||||
int offset = y * width;
|
||||
COUNTER_TYPE* counters = &row_counters[0] + offset;
|
||||
return (COUNTER_TYPE*)counters;
|
||||
}
|
||||
|
||||
COUNTER_TYPE* BitMatrix::getRowRecordsOffset(int y) {
|
||||
if (!row_counters_recorded[y]) {
|
||||
setRowRecords(y);
|
||||
}
|
||||
int offset = y * width;
|
||||
COUNTER_TYPE* counters = &row_counters_offset[0] + offset;
|
||||
return (COUNTER_TYPE*)counters;
|
||||
}
|
||||
|
||||
bool BitMatrix::getRowFirstIsWhite(int y) {
|
||||
bool is_white = !get(0, y);
|
||||
return is_white;
|
||||
}
|
||||
|
||||
bool BitMatrix::getRowLastIsWhite(int y) {
|
||||
bool last_is_white = !get(width - 1, y);
|
||||
return last_is_white;
|
||||
}
|
||||
|
||||
COUNTER_TYPE BitMatrix::getRowCounterOffsetEnd(int y) {
|
||||
if (!row_counters_recorded[y]) {
|
||||
setRowRecords(y);
|
||||
}
|
||||
return row_counter_offset_end[y];
|
||||
}
|
||||
|
||||
void BitMatrix::setRowRecords(int y) {
|
||||
COUNTER_TYPE* cur_row_counters = &row_counters[0] + y * width;
|
||||
COUNTER_TYPE* cur_row_counters_offset = &row_counters_offset[0] + y * width;
|
||||
COUNTER_TYPE* cur_row_point_in_counters = &row_point_offset[0] + y * width;
|
||||
int end = width;
|
||||
|
||||
bool* rowBit = getRowBoolPtr(y);
|
||||
bool isWhite = !rowBit[0];
|
||||
int counterPosition = 0;
|
||||
int i = 0;
|
||||
cur_row_counters_offset[0] = 0;
|
||||
while (i < end) {
|
||||
if (rowBit[i] ^ isWhite) { // that is, exactly one is true
|
||||
cur_row_counters[counterPosition]++;
|
||||
} else {
|
||||
counterPosition++;
|
||||
if (counterPosition == end) {
|
||||
break;
|
||||
} else {
|
||||
cur_row_counters[counterPosition] = 1;
|
||||
isWhite = !isWhite;
|
||||
cur_row_counters_offset[counterPosition] = i;
|
||||
}
|
||||
}
|
||||
cur_row_point_in_counters[i] = counterPosition;
|
||||
i++;
|
||||
}
|
||||
|
||||
// use the last row__onedReaderData->counter_size to record
|
||||
// _onedReaderData->counter_size
|
||||
row_counter_offset_end[y] = counterPosition < end ? (counterPosition + 1) : end;
|
||||
|
||||
row_counters_recorded[y] = true;
|
||||
return;
|
||||
}
|
||||
|
||||
COUNTER_TYPE* BitMatrix::getColsPointInRecords(int x) {
|
||||
if (!cols_point_offset[x]) {
|
||||
setColsRecords(x);
|
||||
}
|
||||
int offset = x * height;
|
||||
COUNTER_TYPE* counters = &cols_point_offset[0] + offset;
|
||||
return (COUNTER_TYPE*)counters;
|
||||
}
|
||||
|
||||
COUNTER_TYPE* BitMatrix::getColsRecords(int x) {
|
||||
if (!cols_counters_recorded[x]) {
|
||||
setColsRecords(x);
|
||||
}
|
||||
int offset = x * height;
|
||||
COUNTER_TYPE* counters = &cols_counters[0] + offset;
|
||||
return (COUNTER_TYPE*)counters;
|
||||
}
|
||||
|
||||
COUNTER_TYPE* BitMatrix::getColsRecordsOffset(int x) {
|
||||
if (!cols_counters_recorded[x]) {
|
||||
setColsRecords(x);
|
||||
}
|
||||
int offset = x * height;
|
||||
COUNTER_TYPE* counters = &cols_counters_offset[0] + offset;
|
||||
return (COUNTER_TYPE*)counters;
|
||||
}
|
||||
|
||||
COUNTER_TYPE BitMatrix::getColsCounterOffsetEnd(int x) {
|
||||
if (!cols_counters_recorded[x]) {
|
||||
setColsRecords(x);
|
||||
}
|
||||
return cols_counter_offset_end[x];
|
||||
}
|
||||
|
||||
void BitMatrix::setColsRecords(int x) {
|
||||
COUNTER_TYPE* cur_cols_counters = &cols_counters[0] + x * height;
|
||||
COUNTER_TYPE* cur_cols_counters_offset = &cols_counters_offset[0] + x * height;
|
||||
COUNTER_TYPE* cur_cols_point_in_counters = &cols_point_offset[0] + x * height;
|
||||
int end = height;
|
||||
|
||||
bool* rowBit = getRowBoolPtr(0);
|
||||
bool isWhite = !rowBit[0];
|
||||
int counterPosition = 0;
|
||||
int i = 0;
|
||||
cur_cols_counters_offset[0] = 0;
|
||||
while (i < end) {
|
||||
if (rowBit[i] ^ isWhite) { // that is, exactly one is true
|
||||
cur_cols_counters[counterPosition]++;
|
||||
} else {
|
||||
counterPosition++;
|
||||
if (counterPosition == end) {
|
||||
break;
|
||||
} else {
|
||||
cur_cols_counters[counterPosition] = 1;
|
||||
isWhite = !isWhite;
|
||||
cur_cols_counters_offset[counterPosition] = i;
|
||||
}
|
||||
}
|
||||
cur_cols_point_in_counters[i] = counterPosition;
|
||||
i++;
|
||||
rowBit += width;
|
||||
}
|
||||
|
||||
cols_counter_offset_end[x] = counterPosition < end ? (counterPosition + 1) : end;
|
||||
|
||||
cols_counters_recorded[x] = true;
|
||||
return;
|
||||
};
|
|
@ -0,0 +1,115 @@
|
|||
// This file is part of OpenCV project.
|
||||
// It is subject to the license terms in the LICENSE file found in the top-level directory
|
||||
// of this distribution and at http://opencv.org/license.html.
|
||||
//
|
||||
// Tencent is pleased to support the open source community by making WeChat QRCode available.
|
||||
// Copyright (C) 2020 THL A29 Limited, a Tencent company. All rights reserved.
|
||||
//
|
||||
// Modified from ZXing. Copyright ZXing authors.
|
||||
// Licensed under the Apache License, Version 2.0 (the "License").
|
||||
|
||||
#ifndef __ZXING_COMMON_BITMATRIX_HPP__
|
||||
#define __ZXING_COMMON_BITMATRIX_HPP__
|
||||
|
||||
#include "../errorhandler.hpp"
|
||||
#include "array.hpp"
|
||||
#include "bitarray.hpp"
|
||||
#include "counted.hpp"
|
||||
using namespace std;
|
||||
|
||||
namespace zxing {
|
||||
|
||||
class BitMatrix : public Counted {
|
||||
public:
|
||||
static const int bitsPerWord = std::numeric_limits<unsigned int>::digits;
|
||||
|
||||
private:
|
||||
int width;
|
||||
int height;
|
||||
int rowBitsSize;
|
||||
|
||||
vector<COUNTER_TYPE> row_counters;
|
||||
vector<COUNTER_TYPE> row_counters_offset;
|
||||
vector<bool> row_counters_recorded;
|
||||
vector<COUNTER_TYPE> row_counter_offset_end;
|
||||
vector<COUNTER_TYPE> row_point_offset;
|
||||
|
||||
vector<COUNTER_TYPE> cols_counters;
|
||||
vector<COUNTER_TYPE> cols_counters_offset;
|
||||
vector<bool> cols_counters_recorded;
|
||||
vector<COUNTER_TYPE> cols_counter_offset_end;
|
||||
vector<COUNTER_TYPE> cols_point_offset;
|
||||
|
||||
ArrayRef<unsigned char> bits;
|
||||
ArrayRef<int> rowOffsets;
|
||||
|
||||
public:
|
||||
BitMatrix(int _width, int _height, unsigned char* bitsPtr, ErrorHandler& err_handler);
|
||||
BitMatrix(int dimension, ErrorHandler& err_handler);
|
||||
BitMatrix(int _width, int _height, ErrorHandler& err_handler);
|
||||
|
||||
void copyOf(Ref<BitMatrix> _bits, ErrorHandler& err_handler);
|
||||
void xxor(Ref<BitMatrix> _bits);
|
||||
|
||||
~BitMatrix();
|
||||
|
||||
unsigned char get(int x, int y) const { return bits[width * y + x]; }
|
||||
|
||||
void set(int x, int y) { bits[rowOffsets[y] + x] = (unsigned char)1; }
|
||||
|
||||
void set(int x, int y, unsigned char value) { bits[rowOffsets[y] + x] = value; }
|
||||
|
||||
void swap(int srcX, int srcY, int dstX, int dstY) {
|
||||
auto temp = bits[width * srcY + srcX];
|
||||
bits[width * srcY + srcX] = bits[width * dstY + dstX];
|
||||
bits[width * dstY + dstX] = temp;
|
||||
}
|
||||
|
||||
void getRowBool(int y, bool* row);
|
||||
bool* getRowBoolPtr(int y);
|
||||
void setRowBool(int y, bool* row);
|
||||
int getRowBitsSize() { return rowBitsSize; }
|
||||
unsigned char* getPtr() { return bits->data(); }
|
||||
|
||||
void flip(int x, int y);
|
||||
void flipAll();
|
||||
void clear();
|
||||
void setRegion(int left, int top, int _width, int _height, ErrorHandler& err_handler);
|
||||
void flipRegion(int left, int top, int _width, int _height, ErrorHandler& err_handler);
|
||||
Ref<BitArray> getRow(int y, Ref<BitArray> row);
|
||||
|
||||
int getWidth() const;
|
||||
int getHeight() const;
|
||||
|
||||
ArrayRef<int> getTopLeftOnBit() const;
|
||||
ArrayRef<int> getBottomRightOnBit() const;
|
||||
|
||||
bool isInitRowCounters;
|
||||
void initRowCounters();
|
||||
COUNTER_TYPE* getRowRecords(int y);
|
||||
COUNTER_TYPE* getRowRecordsOffset(int y);
|
||||
bool getRowFirstIsWhite(int y);
|
||||
COUNTER_TYPE getRowCounterOffsetEnd(int y);
|
||||
bool getRowLastIsWhite(int y);
|
||||
COUNTER_TYPE* getRowPointInRecords(int y);
|
||||
|
||||
bool isInitColsCounters;
|
||||
void initColsCounters();
|
||||
COUNTER_TYPE* getColsRecords(int x);
|
||||
COUNTER_TYPE* getColsRecordsOffset(int x);
|
||||
COUNTER_TYPE* getColsPointInRecords(int x);
|
||||
COUNTER_TYPE getColsCounterOffsetEnd(int x);
|
||||
|
||||
private:
|
||||
inline void init(int, int, ErrorHandler& err_handler);
|
||||
inline void init(int _width, int _height, unsigned char* bitsPtr, ErrorHandler& err_handler);
|
||||
|
||||
void setRowRecords(int y);
|
||||
void setColsRecords(int x);
|
||||
|
||||
BitMatrix(const BitMatrix&, ErrorHandler& err_handler);
|
||||
};
|
||||
|
||||
} // namespace zxing
|
||||
|
||||
#endif // __ZXING_COMMON_BITMATRIX_HPP__
|
|
@ -0,0 +1,62 @@
|
|||
// This file is part of OpenCV project.
|
||||
// It is subject to the license terms in the LICENSE file found in the top-level directory
|
||||
// of this distribution and at http://opencv.org/license.html.
|
||||
//
|
||||
// Tencent is pleased to support the open source community by making WeChat QRCode available.
|
||||
// Copyright (C) 2020 THL A29 Limited, a Tencent company. All rights reserved.
|
||||
//
|
||||
// Modified from ZXing. Copyright ZXing authors.
|
||||
// Licensed under the Apache License, Version 2.0 (the "License").
|
||||
#include "../../precomp.hpp"
|
||||
#include "bitsource.hpp"
|
||||
#include <sstream>
|
||||
|
||||
namespace zxing {
|
||||
|
||||
int BitSource::readBits(int numBits, ErrorHandler& err_handler) {
|
||||
if (numBits < 0 || numBits > 32 || numBits > available()) {
|
||||
std::ostringstream oss;
|
||||
oss << numBits;
|
||||
err_handler = IllegalArgumentErrorHandler(oss.str().c_str());
|
||||
return -1;
|
||||
}
|
||||
|
||||
int result = 0;
|
||||
|
||||
// First, read remainder from current byte
|
||||
if (bitOffset_ > 0) {
|
||||
int bitsLeft = 8 - bitOffset_;
|
||||
int toRead = numBits < bitsLeft ? numBits : bitsLeft;
|
||||
int bitsToNotRead = bitsLeft - toRead;
|
||||
int mask = (0xFF >> (8 - toRead)) << bitsToNotRead;
|
||||
result = (bytes_[byteOffset_] & mask) >> bitsToNotRead;
|
||||
numBits -= toRead;
|
||||
bitOffset_ += toRead;
|
||||
if (bitOffset_ == 8) {
|
||||
bitOffset_ = 0;
|
||||
byteOffset_++;
|
||||
}
|
||||
}
|
||||
|
||||
// Next read whole bytes
|
||||
if (numBits > 0) {
|
||||
while (numBits >= 8) {
|
||||
result = (result << 8) | (bytes_[byteOffset_] & 0xFF);
|
||||
byteOffset_++;
|
||||
numBits -= 8;
|
||||
}
|
||||
|
||||
// Finally read a partial byte
|
||||
if (numBits > 0) {
|
||||
int bitsToNotRead = 8 - numBits;
|
||||
int mask = (0xFF >> bitsToNotRead) << bitsToNotRead;
|
||||
result = (result << numBits) | ((bytes_[byteOffset_] & mask) >> bitsToNotRead);
|
||||
bitOffset_ += numBits;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
int BitSource::available() { return 8 * (bytes_->size() - byteOffset_) - bitOffset_; }
|
||||
} // namespace zxing
|
|
@ -0,0 +1,57 @@
|
|||
// This file is part of OpenCV project.
|
||||
// It is subject to the license terms in the LICENSE file found in the top-level directory
|
||||
// of this distribution and at http://opencv.org/license.html.
|
||||
//
|
||||
// Tencent is pleased to support the open source community by making WeChat QRCode available.
|
||||
// Copyright (C) 2020 THL A29 Limited, a Tencent company. All rights reserved.
|
||||
//
|
||||
// Modified from ZXing. Copyright ZXing authors.
|
||||
// Licensed under the Apache License, Version 2.0 (the "License").
|
||||
|
||||
#ifndef __ZXING_COMMON_BITSOURCE_HPP__
|
||||
#define __ZXING_COMMON_BITSOURCE_HPP__
|
||||
|
||||
#include "../errorhandler.hpp"
|
||||
#include "array.hpp"
|
||||
|
||||
namespace zxing {
|
||||
/**
|
||||
* <p>This provides an easy abstraction to read bits at a time from a sequence
|
||||
* of bytes, where the number of bits read is not often a multiple of 8.</p>
|
||||
*
|
||||
* <p>This class is not thread-safe.</p>
|
||||
*
|
||||
* @author srowen@google.com (Sean Owen)
|
||||
* @author christian.brunschen@gmail.com (Christian Brunschen)
|
||||
*/
|
||||
class BitSource : public Counted {
|
||||
typedef char byte;
|
||||
|
||||
private:
|
||||
ArrayRef<byte> bytes_;
|
||||
int byteOffset_;
|
||||
int bitOffset_;
|
||||
|
||||
public:
|
||||
/**
|
||||
* @param bytes bytes from which this will read bits. Bits will be read from
|
||||
* the first byte first. Bits are read within a byte from most-significant
|
||||
* to least-significant bit.
|
||||
*/
|
||||
explicit BitSource(ArrayRef<byte> &bytes) : bytes_(bytes), byteOffset_(0), bitOffset_(0) {}
|
||||
|
||||
int getBitOffset() { return bitOffset_; }
|
||||
|
||||
int getByteOffset() { return byteOffset_; }
|
||||
|
||||
int readBits(int numBits, ErrorHandler &err_handler);
|
||||
|
||||
/**
|
||||
* @return number of bits that can be read successfully
|
||||
*/
|
||||
int available();
|
||||
};
|
||||
|
||||
} // namespace zxing
|
||||
|
||||
#endif // __ZXING_COMMON_BITSOURCE_HPP__
|
|
@ -0,0 +1,50 @@
|
|||
// This file is part of OpenCV project.
|
||||
// It is subject to the license terms in the LICENSE file found in the top-level directory
|
||||
// of this distribution and at http://opencv.org/license.html.
|
||||
//
|
||||
// Tencent is pleased to support the open source community by making WeChat QRCode available.
|
||||
// Copyright (C) 2020 THL A29 Limited, a Tencent company. All rights reserved.
|
||||
#include "../../precomp.hpp"
|
||||
#include "bytematrix.hpp"
|
||||
|
||||
using zxing::ArrayRef;
|
||||
using zxing::ByteMatrix;
|
||||
using zxing::ErrorHandler;
|
||||
using zxing::Ref;
|
||||
|
||||
void ByteMatrix::init(int _width, int _height) {
|
||||
if (_width < 1 || _height < 1) {
|
||||
return;
|
||||
}
|
||||
this->width = _width;
|
||||
this->height = _height;
|
||||
bytes = new unsigned char[width * height];
|
||||
row_offsets = new int[height];
|
||||
row_offsets[0] = 0;
|
||||
for (int i = 1; i < height; i++) {
|
||||
row_offsets[i] = row_offsets[i - 1] + width;
|
||||
}
|
||||
}
|
||||
|
||||
ByteMatrix::ByteMatrix(int dimension) { init(dimension, dimension); }
|
||||
|
||||
ByteMatrix::ByteMatrix(int _width, int _height) { init(_width, _height); }
|
||||
|
||||
ByteMatrix::ByteMatrix(int _width, int _height, ArrayRef<char> source) {
|
||||
init(_width, _height);
|
||||
int size = _width * _height;
|
||||
memcpy(&bytes[0], &source[0], size);
|
||||
}
|
||||
|
||||
ByteMatrix::~ByteMatrix() {
|
||||
if (bytes) delete[] bytes;
|
||||
if (row_offsets) delete[] row_offsets;
|
||||
}
|
||||
|
||||
unsigned char* ByteMatrix::getByteRow(int y, ErrorHandler& err_handler) {
|
||||
if (y < 0 || y >= getHeight()) {
|
||||
err_handler = IllegalArgumentErrorHandler("Requested row is outside the image.");
|
||||
return NULL;
|
||||
}
|
||||
return &bytes[row_offsets[y]];
|
||||
}
|
|
@ -0,0 +1,58 @@
|
|||
// This file is part of OpenCV project.
|
||||
// It is subject to the license terms in the LICENSE file found in the top-level directory
|
||||
// of this distribution and at http://opencv.org/license.html.
|
||||
//
|
||||
// Tencent is pleased to support the open source community by making WeChat QRCode available.
|
||||
// Copyright (C) 2020 THL A29 Limited, a Tencent company. All rights reserved.
|
||||
|
||||
#ifndef __ZXING_COMMON_BYTEMATRIX_HPP__
|
||||
#define __ZXING_COMMON_BYTEMATRIX_HPP__
|
||||
|
||||
#include "../errorhandler.hpp"
|
||||
#include "array.hpp"
|
||||
#include "bitarray.hpp"
|
||||
#include "counted.hpp"
|
||||
|
||||
namespace zxing {
|
||||
|
||||
class ByteMatrix : public Counted {
|
||||
public:
|
||||
explicit ByteMatrix(int dimension);
|
||||
ByteMatrix(int _width, int _height);
|
||||
ByteMatrix(int _width, int _height, ArrayRef<char> source);
|
||||
~ByteMatrix();
|
||||
|
||||
char get(int x, int y) const {
|
||||
int offset = row_offsets[y] + x;
|
||||
return bytes[offset];
|
||||
}
|
||||
|
||||
void set(int x, int y, char char_value) {
|
||||
int offset = row_offsets[y] + x;
|
||||
bytes[offset] = char_value & 0XFF;
|
||||
}
|
||||
|
||||
unsigned char* getByteRow(int y, ErrorHandler& err_handler);
|
||||
|
||||
int getWidth() const { return width; }
|
||||
int getHeight() const { return height; }
|
||||
|
||||
unsigned char* bytes;
|
||||
|
||||
private:
|
||||
int width;
|
||||
int height;
|
||||
|
||||
// ArrayRef<char> bytes;
|
||||
// ArrayRef<int> row_offsets;
|
||||
int* row_offsets;
|
||||
|
||||
private:
|
||||
inline void init(int, int);
|
||||
ByteMatrix(const ByteMatrix&);
|
||||
ByteMatrix& operator=(const ByteMatrix&);
|
||||
};
|
||||
|
||||
} // namespace zxing
|
||||
|
||||
#endif // __ZXING_COMMON_BYTEMATRIX_HPP__
|
|
@ -0,0 +1,111 @@
|
|||
// This file is part of OpenCV project.
|
||||
// It is subject to the license terms in the LICENSE file found in the top-level directory
|
||||
// of this distribution and at http://opencv.org/license.html.
|
||||
//
|
||||
// Tencent is pleased to support the open source community by making WeChat QRCode available.
|
||||
// Copyright (C) 2020 THL A29 Limited, a Tencent company. All rights reserved.
|
||||
//
|
||||
// Modified from ZXing. Copyright ZXing authors.
|
||||
// Licensed under the Apache License, Version 2.0 (the "License").
|
||||
#include "../../precomp.hpp"
|
||||
#include "characterseteci.hpp"
|
||||
using zxing::common::CharacterSetECI;
|
||||
|
||||
// Fix memory leak
|
||||
// https://github.com/ukeller/zxing-cpp/commit/c632ffe47ca7342f894ae533263be249cbdfd37e
|
||||
// std::map<int, CharacterSetECI*> CharacterSetECI::VALUE_TO_ECI;
|
||||
// std::map<std::string, CharacterSetECI*> CharacterSetECI::NAME_TO_ECI;
|
||||
std::map<int, zxing::Ref<CharacterSetECI> > CharacterSetECI::VALUE_TO_ECI;
|
||||
std::map<std::string, zxing::Ref<CharacterSetECI> > CharacterSetECI::NAME_TO_ECI;
|
||||
|
||||
const bool CharacterSetECI::inited = CharacterSetECI::init_tables();
|
||||
|
||||
#define ADD_CHARACTER_SET(VALUES, STRINGS) \
|
||||
{ \
|
||||
static int values[] = {VALUES, -1}; \
|
||||
static char const* strings[] = {STRINGS, 0}; \
|
||||
addCharacterSet(values, strings); \
|
||||
}
|
||||
|
||||
#define XC ,
|
||||
|
||||
bool CharacterSetECI::init_tables() {
|
||||
ADD_CHARACTER_SET(0 XC 2, "Cp437");
|
||||
ADD_CHARACTER_SET(1 XC 3, "ISO8859_1" XC "ISO-8859-1");
|
||||
ADD_CHARACTER_SET(4, "ISO8859_2" XC "ISO-8859-2");
|
||||
ADD_CHARACTER_SET(5, "ISO8859_3" XC "ISO-8859-3");
|
||||
ADD_CHARACTER_SET(6, "ISO8859_4" XC "ISO-8859-4");
|
||||
ADD_CHARACTER_SET(7, "ISO8859_5" XC "ISO-8859-5");
|
||||
ADD_CHARACTER_SET(8, "ISO8859_6" XC "ISO-8859-6");
|
||||
ADD_CHARACTER_SET(9, "ISO8859_7" XC "ISO-8859-7");
|
||||
ADD_CHARACTER_SET(10, "ISO8859_8" XC "ISO-8859-8");
|
||||
ADD_CHARACTER_SET(11, "ISO8859_9" XC "ISO-8859-9");
|
||||
ADD_CHARACTER_SET(12, "ISO8859_10" XC "ISO-8859-10");
|
||||
ADD_CHARACTER_SET(13, "ISO8859_11" XC "ISO-8859-11");
|
||||
ADD_CHARACTER_SET(15, "ISO8859_13" XC "ISO-8859-13");
|
||||
ADD_CHARACTER_SET(16, "ISO8859_14" XC "ISO-8859-14");
|
||||
ADD_CHARACTER_SET(17, "ISO8859_15" XC "ISO-8859-15");
|
||||
ADD_CHARACTER_SET(18, "ISO8859_16" XC "ISO-8859-16");
|
||||
ADD_CHARACTER_SET(20, "SJIS" XC "Shift_JIS");
|
||||
ADD_CHARACTER_SET(21, "Cp1250" XC "windows-1250");
|
||||
ADD_CHARACTER_SET(22, "Cp1251" XC "windows-1251");
|
||||
ADD_CHARACTER_SET(23, "Cp1252" XC "windows-1252");
|
||||
ADD_CHARACTER_SET(24, "Cp1256" XC "windows-1256");
|
||||
ADD_CHARACTER_SET(25, "UnicodeBigUnmarked" XC "UTF-16BE" XC "UnicodeBig");
|
||||
ADD_CHARACTER_SET(26, "UTF8" XC "UTF-8");
|
||||
ADD_CHARACTER_SET(27 XC 170, "ASCII" XC "US-ASCII");
|
||||
ADD_CHARACTER_SET(28, "Big5");
|
||||
ADD_CHARACTER_SET(29, "GB18030" XC "GB2312" XC "EUC_CN" XC "GBK");
|
||||
ADD_CHARACTER_SET(30, "EUC_KR" XC "EUC-KR");
|
||||
return true;
|
||||
}
|
||||
|
||||
#undef XC
|
||||
|
||||
CharacterSetECI::CharacterSetECI(int const* values, char const* const* names)
|
||||
: values_(values), names_(names) {
|
||||
zxing::Ref<CharacterSetECI> this_ref(this);
|
||||
|
||||
for (int const* p_values = values_; *p_values != -1; p_values++) {
|
||||
// VALUE_TO_ECI[*values] = this;
|
||||
VALUE_TO_ECI[*p_values] = this_ref;
|
||||
}
|
||||
for (char const* const* p_names = names_; *p_names; p_names++) {
|
||||
// NAME_TO_ECI[string(*names)] = this;
|
||||
NAME_TO_ECI[string(*p_names)] = this_ref;
|
||||
}
|
||||
}
|
||||
|
||||
char const* CharacterSetECI::name() const { return names_[0]; }
|
||||
|
||||
int CharacterSetECI::getValue() const { return values_[0]; }
|
||||
|
||||
void CharacterSetECI::addCharacterSet(int const* values, char const* const* names) {
|
||||
new CharacterSetECI(values, names);
|
||||
}
|
||||
|
||||
CharacterSetECI* CharacterSetECI::getCharacterSetECIByValueFind(int value) {
|
||||
if (value < 0 || value >= 900) {
|
||||
return zxing::Ref<CharacterSetECI>(0);
|
||||
}
|
||||
|
||||
std::map<int, zxing::Ref<CharacterSetECI> >::iterator iter;
|
||||
iter = VALUE_TO_ECI.find(value);
|
||||
|
||||
if (iter != VALUE_TO_ECI.end()) {
|
||||
return iter->second;
|
||||
} else {
|
||||
return zxing::Ref<CharacterSetECI>(0);
|
||||
}
|
||||
}
|
||||
|
||||
CharacterSetECI* CharacterSetECI::getCharacterSetECIByName(string const& name) {
|
||||
std::map<std::string, zxing::Ref<CharacterSetECI> >::iterator iter;
|
||||
iter = NAME_TO_ECI.find(name);
|
||||
|
||||
if (iter != NAME_TO_ECI.end()) {
|
||||
return iter->second;
|
||||
} else {
|
||||
return zxing::Ref<CharacterSetECI>(0);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,46 @@
|
|||
// This file is part of OpenCV project.
|
||||
// It is subject to the license terms in the LICENSE file found in the top-level directory
|
||||
// of this distribution and at http://opencv.org/license.html.
|
||||
//
|
||||
// Tencent is pleased to support the open source community by making WeChat QRCode available.
|
||||
// Copyright (C) 2020 THL A29 Limited, a Tencent company. All rights reserved.
|
||||
//
|
||||
// Modified from ZXing. Copyright ZXing authors.
|
||||
// Licensed under the Apache License, Version 2.0 (the "License").
|
||||
|
||||
#ifndef __ZXING_COMMON_CHARACTERSETECI_HPP__
|
||||
#define __ZXING_COMMON_CHARACTERSETECI_HPP__
|
||||
|
||||
#include <map>
|
||||
#include "../decodehints.hpp"
|
||||
#include "counted.hpp"
|
||||
|
||||
namespace zxing {
|
||||
namespace common {
|
||||
|
||||
class CharacterSetECI : public Counted {
|
||||
private:
|
||||
static std::map<int, zxing::Ref<CharacterSetECI> > VALUE_TO_ECI;
|
||||
static std::map<std::string, zxing::Ref<CharacterSetECI> > NAME_TO_ECI;
|
||||
static const bool inited;
|
||||
static bool init_tables();
|
||||
|
||||
int const* const values_;
|
||||
char const* const* const names_;
|
||||
|
||||
CharacterSetECI(int const* values, char const* const* names);
|
||||
|
||||
static void addCharacterSet(int const* value, char const* const* encodingNames);
|
||||
|
||||
public:
|
||||
char const* name() const;
|
||||
int getValue() const;
|
||||
|
||||
static CharacterSetECI* getCharacterSetECIByValueFind(int value);
|
||||
static CharacterSetECI* getCharacterSetECIByName(std::string const& name);
|
||||
};
|
||||
|
||||
} // namespace common
|
||||
} // namespace zxing
|
||||
|
||||
#endif // __ZXING_COMMON_CHARACTERSETECI_HPP__
|
|
@ -0,0 +1,110 @@
|
|||
// This file is part of OpenCV project.
|
||||
// It is subject to the license terms in the LICENSE file found in the top-level directory
|
||||
// of this distribution and at http://opencv.org/license.html.
|
||||
//
|
||||
// Tencent is pleased to support the open source community by making WeChat QRCode available.
|
||||
// Copyright (C) 2020 THL A29 Limited, a Tencent company. All rights reserved.
|
||||
//
|
||||
// Modified from ZXing. Copyright ZXing authors.
|
||||
// Licensed under the Apache License, Version 2.0 (the "License").
|
||||
|
||||
#ifndef __ZXING_COMMON_COUNTED_HPP__
|
||||
#define __ZXING_COMMON_COUNTED_HPP__
|
||||
|
||||
#include <cstddef>
|
||||
#include <algorithm>
|
||||
namespace zxing {
|
||||
|
||||
/* base class for reference-counted objects */
|
||||
class Counted {
|
||||
private:
|
||||
unsigned int count_;
|
||||
|
||||
public:
|
||||
Counted() : count_(0) {}
|
||||
virtual ~Counted() {}
|
||||
Counted* retain() {
|
||||
count_++;
|
||||
return this;
|
||||
}
|
||||
void release() {
|
||||
count_--;
|
||||
if (count_ == 0) {
|
||||
count_ = 0xDEADF001;
|
||||
delete this;
|
||||
}
|
||||
}
|
||||
|
||||
/* return the current count for denugging purposes or similar */
|
||||
int count() const { return count_; }
|
||||
};
|
||||
|
||||
/* counting reference to reference-counted objects */
|
||||
template <typename T>
|
||||
class Ref {
|
||||
private:
|
||||
public:
|
||||
T* object_;
|
||||
explicit Ref(T* o = 0) : object_(0) { reset(o); }
|
||||
Ref(const Ref& other) : object_(0) { reset(other.object_); }
|
||||
|
||||
template <class Y>
|
||||
Ref(const Ref<Y>& other) : object_(0) {
|
||||
reset(other.object_);
|
||||
}
|
||||
|
||||
~Ref() {
|
||||
if (object_) {
|
||||
object_->release();
|
||||
}
|
||||
}
|
||||
|
||||
void reset(T* o) {
|
||||
if (o) {
|
||||
o->retain();
|
||||
}
|
||||
if (object_ != 0) {
|
||||
object_->release();
|
||||
}
|
||||
object_ = o;
|
||||
}
|
||||
Ref& operator=(const Ref& other) {
|
||||
reset(other.object_);
|
||||
return *this;
|
||||
}
|
||||
template <class Y>
|
||||
Ref& operator=(const Ref<Y>& other) {
|
||||
reset(other.object_);
|
||||
return *this;
|
||||
}
|
||||
Ref& operator=(T* o) {
|
||||
reset(o);
|
||||
return *this;
|
||||
}
|
||||
template <class Y>
|
||||
Ref& operator=(Y* o) {
|
||||
reset(o);
|
||||
return *this;
|
||||
}
|
||||
|
||||
T& operator*() { return *object_; }
|
||||
T* operator->() const { return object_; }
|
||||
operator T*() const { return object_; }
|
||||
|
||||
bool operator==(const T* that) { return object_ == that; }
|
||||
bool operator==(const Ref& other) const {
|
||||
return object_ == other.object_ || *object_ == *(other.object_);
|
||||
}
|
||||
template <class Y>
|
||||
bool operator==(const Ref<Y>& other) const {
|
||||
return object_ == other.object_ || *object_ == *(other.object_);
|
||||
}
|
||||
|
||||
bool operator!=(const T* that) { return !(*this == that); }
|
||||
|
||||
bool empty() const { return object_ == 0; }
|
||||
};
|
||||
|
||||
} // namespace zxing
|
||||
|
||||
#endif // __ZXING_COMMON_COUNTED_HPP__
|
|
@ -0,0 +1,65 @@
|
|||
// This file is part of OpenCV project.
|
||||
// It is subject to the license terms in the LICENSE file found in the top-level directory
|
||||
// of this distribution and at http://opencv.org/license.html.
|
||||
//
|
||||
// Tencent is pleased to support the open source community by making WeChat QRCode available.
|
||||
// Copyright (C) 2020 THL A29 Limited, a Tencent company. All rights reserved.
|
||||
//
|
||||
// Modified from ZXing. Copyright ZXing authors.
|
||||
// Licensed under the Apache License, Version 2.0 (the "License").
|
||||
#include "../../precomp.hpp"
|
||||
#include "decoder_result.hpp"
|
||||
|
||||
using zxing::DecoderResult;
|
||||
using zxing::Ref;
|
||||
using zxing::ArrayRef;
|
||||
using zxing::String;
|
||||
DecoderResult::DecoderResult(ArrayRef<char> rawBytes, Ref<String> text,
|
||||
ArrayRef<ArrayRef<char> >& byteSegments, string const& ecLevel)
|
||||
: rawBytes_(rawBytes), text_(text), byteSegments_(byteSegments), ecLevel_(ecLevel) {
|
||||
outputCharset_ = "UTF-8";
|
||||
otherClassName = "";
|
||||
qrcodeVersion_ = -1;
|
||||
}
|
||||
|
||||
DecoderResult::DecoderResult(ArrayRef<char> rawBytes, Ref<String> text,
|
||||
ArrayRef<ArrayRef<char> >& byteSegments, string const& ecLevel,
|
||||
string outputCharset)
|
||||
: rawBytes_(rawBytes),
|
||||
text_(text),
|
||||
byteSegments_(byteSegments),
|
||||
ecLevel_(ecLevel),
|
||||
outputCharset_(outputCharset) {
|
||||
otherClassName = "";
|
||||
qrcodeVersion_ = -1;
|
||||
}
|
||||
|
||||
DecoderResult::DecoderResult(ArrayRef<char> rawBytes, Ref<String> text,
|
||||
ArrayRef<ArrayRef<char> >& byteSegments, string const& ecLevel,
|
||||
string outputCharset, int qrcodeVersion, string& charsetMode)
|
||||
: rawBytes_(rawBytes),
|
||||
text_(text),
|
||||
byteSegments_(byteSegments),
|
||||
ecLevel_(ecLevel),
|
||||
outputCharset_(outputCharset),
|
||||
qrcodeVersion_(qrcodeVersion),
|
||||
charsetMode_(charsetMode) {
|
||||
otherClassName = "";
|
||||
}
|
||||
|
||||
DecoderResult::DecoderResult(ArrayRef<char> rawBytes, Ref<String> text)
|
||||
: rawBytes_(rawBytes), text_(text) {
|
||||
outputCharset_ = "UTF-8";
|
||||
otherClassName = "";
|
||||
}
|
||||
|
||||
DecoderResult::DecoderResult(ArrayRef<char> rawBytes, Ref<String> text, std::string outputCharset)
|
||||
: rawBytes_(rawBytes), text_(text), outputCharset_(outputCharset) {
|
||||
otherClassName = "";
|
||||
}
|
||||
|
||||
ArrayRef<char> DecoderResult::getRawBytes() { return rawBytes_; }
|
||||
|
||||
Ref<String> DecoderResult::getText() { return text_; }
|
||||
|
||||
string DecoderResult::getCharset() { return outputCharset_; }
|
|
@ -0,0 +1,77 @@
|
|||
// This file is part of OpenCV project.
|
||||
// It is subject to the license terms in the LICENSE file found in the top-level directory
|
||||
// of this distribution and at http://opencv.org/license.html.
|
||||
//
|
||||
// Tencent is pleased to support the open source community by making WeChat QRCode available.
|
||||
// Copyright (C) 2020 THL A29 Limited, a Tencent company. All rights reserved.
|
||||
//
|
||||
// Modified from ZXing. Copyright ZXing authors.
|
||||
// Licensed under the Apache License, Version 2.0 (the "License").
|
||||
|
||||
#ifndef __ZXING_COMMON_DECODER_RESULT_HPP__
|
||||
#define __ZXING_COMMON_DECODER_RESULT_HPP__
|
||||
|
||||
#include "../qrcode/decoder/qrcode_decoder_metadata.hpp"
|
||||
#include "array.hpp"
|
||||
#include "counted.hpp"
|
||||
#include "str.hpp"
|
||||
|
||||
namespace zxing {
|
||||
|
||||
class DecoderResult : public Counted {
|
||||
private:
|
||||
ArrayRef<char> rawBytes_;
|
||||
Ref<String> text_;
|
||||
ArrayRef<ArrayRef<char> > byteSegments_;
|
||||
std::string ecLevel_;
|
||||
std::string outputCharset_;
|
||||
int qrcodeVersion_;
|
||||
std::string charsetMode_;
|
||||
|
||||
Ref<qrcode::QRCodeDecoderMetaData> other_;
|
||||
string otherClassName;
|
||||
|
||||
public:
|
||||
DecoderResult(ArrayRef<char> rawBytes, Ref<String> text,
|
||||
ArrayRef<ArrayRef<char> >& byteSegments, std::string const& ecLevel);
|
||||
|
||||
DecoderResult(ArrayRef<char> rawBytes, Ref<String> text,
|
||||
ArrayRef<ArrayRef<char> >& byteSegments, std::string const& ecLevel,
|
||||
std::string outputCharset);
|
||||
|
||||
DecoderResult(ArrayRef<char> rawBytes, Ref<String> text,
|
||||
ArrayRef<ArrayRef<char> >& byteSegments, std::string const& ecLevel,
|
||||
std::string outputCharset, int qrcodeVersion, std::string& charsetMode);
|
||||
|
||||
DecoderResult(ArrayRef<char> rawBytes, Ref<String> text);
|
||||
|
||||
DecoderResult(ArrayRef<char> rawBytes, Ref<String> text, std::string outputCharset);
|
||||
|
||||
ArrayRef<char> getRawBytes();
|
||||
Ref<String> getText();
|
||||
std::string getCharset();
|
||||
|
||||
void setOther(Ref<qrcode::QRCodeDecoderMetaData> other) {
|
||||
other_ = other;
|
||||
otherClassName = "QRCodeDecoderMetaData";
|
||||
};
|
||||
|
||||
Ref<qrcode::QRCodeDecoderMetaData> getOther() {
|
||||
// className = otherClassName;
|
||||
return other_;
|
||||
};
|
||||
|
||||
string getOtherClassName() { return otherClassName; };
|
||||
|
||||
int getQRCodeVersion() const { return qrcodeVersion_; };
|
||||
|
||||
void setText(Ref<String> text) { text_ = text; };
|
||||
|
||||
string getEcLevel() { return ecLevel_; }
|
||||
|
||||
string getCharsetMode() { return charsetMode_; }
|
||||
};
|
||||
|
||||
} // namespace zxing
|
||||
|
||||
#endif // __ZXING_COMMON_DECODER_RESULT_HPP__
|