Commit 9d181264 authored by Gabrielle Brandenburg dos Anjos's avatar Gabrielle Brandenburg dos Anjos
Browse files

add files

parents
cmake_minimum_required( VERSION 2.8 )
set( _LIB_NAME SegmentedStructureDiameter )
project( ${_LIB_NAME} )
if( CMAKE_BUILD_TYPE MATCHES "Debug" )
set( CONFIGURATION debug )
else()
set( CONFIGURATION release )
endif()
set( _LIB_PATH .. )
include_directories( ${_LIB_PATH}/src )
include_directories( ${V3O2_LIB_INC} )
set( _LIB_SOURCES
${_LIB_PATH}/src/Graph.cpp
${_LIB_PATH}/src/ImageGraph.cpp
${_LIB_PATH}/src/Image.cpp
${_LIB_PATH}/src/Pixel.cpp
${_LIB_PATH}/src/SegmentedStructureDiameters.cpp
)
add_library( ${_LIB_NAME} STATIC
${_LIB_SOURCES} )
if ( CMAKE_BUILD_TYPE MATCHES "Debug" )
set_target_properties( ${_LIB_NAME} PROPERTIES COMPILE_OPTIONS -g )
else()
set_target_properties( ${_LIB_NAME} PROPERTIES COMPILE_OPTIONS -O2 )
endif()
file( MAKE_DIRECTORY ${_LIB_PATH}/lib/ )
set_target_properties( ${_LIB_NAME} PROPERTIES
ARCHIVE_OUTPUT_DIRECTORY ${_LIB_PATH}/lib/${CONFIGURATION}/${UNAME}/
ARCHIVE_OUTPUT_NAME ${_LIB_NAME}
COMPILE_FLAGS "-c -fPIC -fopenmp -Wall -Wno-nonnull-compare -std=c++17 -DLITTLE_ENDIAN -D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE"
)
Para compilar a lib:
1) Entrar no ambiente do devtoolset-2.
2) Comando: path_v3o2/dependecies/ext/cmake/bin/cmake -DCMAKE_BUILD_TYPE="Release"
3) Comando: make
#pragma once
#include <iostream>
#include <algorithm>
/**
* @namespace SegmentedStructureDiameters
*/
namespace SegmentedStructureDiameters
{
/**
*
* Classe de uma imagem 2D de tipo genérico T.
* @class DigitalImage
*/
template<typename T>
class DigitalImage
{
public:
/**
* Construtor que recebe o numero linhas e colunas
* Constrói imagem vazia
* @param rows
* @param cols
*/
DigitalImage(int rows = 0, int cols = 0):
_rows(rows),
_cols(cols),
_size(static_cast<size_t>(rows * cols)),
_data(nullptr),
_ownData(true)
{
if (_size != 0)
_data = new T[_size];
}
/**
* Construtor que recebe o numero linhas e colunas e um valor constante.
* Constrói imagem com todas as amostrar preenchidas com o valor constante.
* @param rows altura da imagem
* @param cols largura da imagem
* @param value valor constante que preenche a imagem
*/
DigitalImage(int rows, int cols, const T& value ):
DigitalImage(rows, cols)
{
std::fill_n(_data, _size, value);
}
/**
* Construtor que recebe o numero linhas e colunas e os dados.
* Constrói imagem e preenche com os dados recebidos em data.
* Não é owner do dado armazenado (não faz copia ou move para dentro da classe)
* @param rows altura da imagem
* @param cols largura da imagem
* @param data vetor de dados a ser armazenado na imagem
*/
DigitalImage(int rows, int cols, T* data):
_rows(rows),
_cols(cols),
_size(static_cast<size_t>(rows * cols)),
_data(data),
_ownData(false)
{
}
/**
* Construtor que recebe o numero linhas e colunas e os dados.
* Constrói imagem e preenche com os dados recebidos.
* Pode ser owner do vetor de dados caso ownData = true
* @param rows
* @param cols
* @param data
* @param ownData Se true, copia o vetor de dados para dentro da classe
*/
DigitalImage(int rows, int cols, T* data, bool ownData) :
_rows(rows),
_cols(cols),
_size(static_cast<size_t>(rows* cols)),
_ownData(ownData)
{
if (ownData)
{
_data = new T[_size];
std::copy_n(data, _size, _data);
}
else
{
_data = data;
}
}
/**
* Construtor de copia
* @param image a ser copiada
*/
DigitalImage(const DigitalImage& image) :
_rows(image._rows),
_cols(image._cols),
_size(_rows* _cols),
_data(nullptr),
_ownData(image._ownData)
{
if(!_ownData)
_data = image._data;
else
{
_data = new T[_size];
std::copy(image._data, image._data + _size, _data);
}
}
/**
* Construtor de copia
* @param image
*/
DigitalImage(DigitalImage&& image) noexcept :
_rows(image._rows),
_cols(image._cols),
_size(_rows*_cols),
_data(image._data),
_ownData(image._ownData)
{
image._data = nullptr;
image._ownData = false;
image._size = 0;
image._cols = 0;
image._rows = 0;
}
/**
* Operador de atribuicão
* Copia o dado no caso de rhs ser owner do dado
* @param rhs
*/
DigitalImage& operator=(const DigitalImage& rhs)
{
_rows = rhs._rows;
_cols = rhs._cols;
_size = _rows * _cols;
_ownData = rhs._ownData;
if(!_ownData)
{
_data = rhs._data;
}
else
{
delete _data;
_data = new T[_size];
std::copy(rhs._data, rhs._data + _size, _data);
}
return *this;
}
/**
* Operador de atribuicão
* Copia o dado no caso de rhs ser owner do dado
* @param rhs
*/
DigitalImage& operator=(DigitalImage&& rhs) noexcept
{
_rows = rhs._rows;
_cols = rhs._cols;
_size = _rows * _cols;
_ownData = rhs._ownData;
_data= rhs._data;
rhs._data = nullptr;
rhs._ownData = false;
rhs._size = 0;
rhs._cols = 0;
rhs._rows = 0;
return *this;
}
/**
* Destrutor
*/
~DigitalImage()
{
if(_ownData)
delete []_data;
}
/**
* Operador de acesso pelo índice a uma amostra
* @param index
*/
T& at(int index)
{
return _data[index];
}
/**
* Operador de acesso constante pelo índice a uma amostra
* @param index
*/
const T& at(int index) const
{
return _data[index];
}
/**
* Operador de acesso a uma amostra pelas coordenadas
* @param row coordenada Y
* @param column coordenada X
*/
T& at(int row, int column)
{
return at(row * _cols + column);
}
/**
* Operador de acesso constante a uma amostra pelas coordenadas
* @param row coordenada Y
* @param column coordenada X
*/
const T& at(int row, int column) const
{
return at(row * _cols + column);
}
/**
* Acesso ao dado armazenado na imagem
*/
T* data()
{
return _data;
}
/**
* Acesso ao dado armazenado na imagem
*/
const T* data() const
{
return _data;
}
/**
* Quantidade de amostras da imagem
*/
size_t size() const
{
return _size;
}
/**
* Tamanho em bytes do tipo da imagem
*/
size_t elemSize() const
{
return sizeof(T);
}
/**
* Altura da imagem
*/
int rows() const
{
return _rows;
}
/**
* Largura da imagem
*/
int cols() const
{
return _cols;
}
/**
* Operador de comparacão entre duas imagens
* @param img
*/
bool operator==(const DigitalImage<T>& img) const
{
return (_cols == img._cols && _rows == img._rows &&
std::equal(_data, _data + _size, img._data));
}
/**
* Limpa a imagem e preenche com parâmetro value
* @param value Valor constante para preencher a imagem
*/
void clear(T value = static_cast<T>(0))
{
std::fill(_data, _data + _size, value);
}
/**
* Operador de impressão
*/
template<typename K> friend std::ostream& operator<<(std::ostream& os, const DigitalImage<K>& img);
private:
int _rows;
int _cols;
size_t _size;
T* _data;
bool _ownData; // indica se buffer de dados foi alocado na propria estrutura
};
template<typename T>
std::ostream& operator<<(std::ostream& stream, const DigitalImage<T>& img)
{
if(img._cols < 1)
return stream;
stream << "[";
for(int j = 0; j < img._rows; j++)
{
T* ptr = img._data + j * img._cols;
stream << " " << ptr[0];
for(int i = 1; i < img._cols;i++)
stream << ", " << ptr[i];
stream << ";" << std::endl;
}
stream << "]" << std::endl;
return stream;
}
using DigitalImageUChar = DigitalImage<unsigned char>;
using DigitalImageFloat = DigitalImage<float>;
using DigitalImageDouble = DigitalImage<double>;
using DigitalImageInt = DigitalImage<int>;
using DigitalImageUInt = DigitalImage<unsigned int>;
}
/*
* File: Graph.cpp
* Author: jcoelho
*
* Created on 5 de Junho de 2018, 12:44
*/
#include <vector>
#include <cstdio>
#include <queue>
#include <stack>
#include <cmath>
#include <cstdlib>
#include <algorithm>
#include "Graph.h"
#include <chrono>
#include <iostream>
#include <queue>
namespace SegmentedStructureDiameters {
Graph::Graph( unsigned int n )
{
_adj.resize( n );
_n = n;
}
void Graph::addEdge( unsigned int v, const Edge& e )
{
if (v < _n)
{
_adj[v].push_back( e );
}
else
{
printf( "Erro ao inserir aresta ao nó %d\n", v );
}
}
void Graph::addEdge( unsigned int v, unsigned int u )
{
if (v < _n)
{
Edge e;
e._d = 1.0f;
e._j = u;
_adj[v].push_back(e);
}
else
{
printf( "Erro ao inserir aresta ao nó %d\n", v );
}
}
const Graph::Edge& Graph::getEdge( unsigned int v, unsigned int idx ) const
{
return _adj[v][idx];
}
unsigned int Graph::degree( unsigned int v ) const
{
return static_cast<unsigned int>(_adj[v].size( ));
}
unsigned int Graph::size( ) const
{
return static_cast<unsigned int>(_adj.size( ));
}
unsigned int Graph::simplifyGraph( const std::vector<bool>& nodesOnGraph )
{
//Verifica se o vetor é compatível com o número de nós no grafo corrente.
if (nodesOnGraph.size( ) != _n)
return _n;
//Inicializa o contador de número de nós no grafo.
_n = 0;
//Vetor para armazenar a nova indexação dos nós do grafo.
std::vector<int> reindex( nodesOnGraph.size( ), -1 );
for (unsigned int i = 0; i < nodesOnGraph.size( ); i++)
{
if (nodesOnGraph[i])
{
reindex[i] = static_cast<int>(_n);
_n++;
}
}
//Se nenhum nó estiver no grafo, então vira um grafo vazio. Provavelmente um erro ocorreu aqui.
if (_n == 0)
{
//Limpa vetores.
_adj.clear( );
return _n;
}
//Obtém as arestas do novo grafo.
buildNewGraphTopology( nodesOnGraph, reindex);
return _n;
}
//@TODO: optimize me!
std::pair<unsigned int, unsigned int> Graph::floydWarshall( std::vector<std::vector<float>>&dist ) const
{
if(_n == 0)
{
return std::make_pair(-1, -1);
}
//Aloca matrizes.
dist.resize(_n);
const float INF = 1e6;
for(unsigned int i = 0; i < _n; i++)
{
dist[i].resize(_n, INF);
dist[i][i] = 0.0f;
}
//Inicializa matrizes.
for(unsigned int i = 0; i < _n; i++)
{
for(unsigned int j = 0; j < degree(i); j++)
{
unsigned int w = _adj[i][j]._j;
dist[i][w] = std::min(_adj[i][j]._d, dist[i][w]);
}
}
//Calcula a menor distância entre cada par de pontos no grafo.
for(unsigned int k = 0; k < _n; k++)
{
for(unsigned int i = 0; i < _n; i++)
{
//If dist[i][k] = INF, then dist[i][k] + dist[k][j] will never be less than dist[i][j]. So, the internal
//for do not must be executed.
if(std::fabs(dist[i][k] - INF) > 1e-8f)
{
for(unsigned int j = 0; j <= i; j++)
{
if(dist[i][k] + dist[k][j] < dist[i][j])
{
dist[i][j] = dist[j][i] = dist[i][k] + dist[k][j];
}
}
}
}
}
//Encontra o par de nós mais distantes no grafo.
std::pair<unsigned int, unsigned int> maxP(0, 0);
float maxDistance = -1.0f;
for(unsigned int i = 0; i < _n; i++)
{
for(unsigned int j = 0; j < i; j++)
{
//Prevent disconnected graphs.
if(std::fabs(dist[i][j] - INF) > 1e-8f && dist[i][j] > maxDistance)
{
maxDistance = dist[i][j];
maxP.first = i;
maxP.second = j;
}
}
}
return maxP;
}
Graph::Diameter Graph::computeDiameter() const
{
constexpr auto INF = std::numeric_limits<float>::infinity();
auto ret = Diameter{-1.0f, 0, 0};
struct VertDist
{
unsigned int id;
float dist;
bool operator<(const VertDist& o) const { return dist > o.dist; } // lower priority means higher distance
};
auto queue = std::priority_queue<VertDist>{};
auto dist = std::vector<float>(_n);
auto prev = std::vector<std::vector<int>>(_n, std::vector<int>(_n, -1));
for(unsigned int i = 0; i < _n; ++i)
{
// begin dijkstra's algorithm for single-source shortest paths
std::fill(dist.begin(), dist.end(), INF);
dist[i] = 0.0f;
queue.push({i, 0.0f});
while(!queue.empty())
{
const auto [u, distU] = queue.top();
queue.pop();
for(const auto [v, distUV] : _adj[u])
{
auto& distV = dist[v];
const auto altDist = distU + distUV;
if(altDist < distV)
{
distV = altDist;
prev[i][v] = u;
queue.push({v, altDist});
}
}
}
// end dijkstra's algorithm for single-source shortest paths
// find longest of shortest paths computed by dijkstra
for(unsigned int v = 0; v < dist.size(); ++v)
{
const auto d = dist[v];
if(d < INF && d > ret.distance)
{
ret.distance = d;
ret.n1 = i;
ret.n2 = v;
}
}