Skip to content

Commit

Permalink
Add extra patch
Browse files Browse the repository at this point in the history
  • Loading branch information
mattdawkins committed Aug 18, 2023
1 parent 226a1d5 commit c248dd9
Show file tree
Hide file tree
Showing 3 changed files with 280 additions and 0 deletions.
96 changes: 96 additions & 0 deletions packages/patches/pydensecrf/pydensecrf/densecrf.pxd
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
from .eigen cimport *


cdef extern from "densecrf/include/labelcompatibility.h":
cdef cppclass LabelCompatibility:
pass

cdef cppclass PottsCompatibility(LabelCompatibility):
PottsCompatibility(float) except +

cdef cppclass DiagonalCompatibility(LabelCompatibility):
DiagonalCompatibility(const c_VectorXf&) except +

cdef cppclass MatrixCompatibility(LabelCompatibility):
MatrixCompatibility(const c_MatrixXf&) except +


cdef extern from "densecrf/include/unary.h":
cdef cppclass UnaryEnergy:
pass

cdef cppclass ConstUnaryEnergy(UnaryEnergy):
ConstUnaryEnergy(const c_MatrixXf& unary) except +

cdef cppclass LogisticUnaryEnergy(UnaryEnergy):
LogisticUnaryEnergy(const c_MatrixXf& L, const c_MatrixXf& feature) except +


cdef class Unary:
cdef UnaryEnergy *thisptr
cdef UnaryEnergy* move(self)


cdef class ConstUnary(Unary):
pass


cdef class LogisticUnary(Unary):
pass


cdef extern from "densecrf/include/pairwise.h":
cpdef enum NormalizationType: NO_NORMALIZATION, NORMALIZE_BEFORE, NORMALIZE_AFTER, NORMALIZE_SYMMETRIC
cpdef enum KernelType: CONST_KERNEL, DIAG_KERNEL, FULL_KERNEL


cdef extern from "densecrf/include/densecrf.h":
cdef cppclass c_DenseCRF "DenseCRF":
c_DenseCRF(int N, int M) except +

# Setup methods.
# TODO
#void addPairwiseEnergy(PairwisePotential *potential)
void addPairwiseEnergy(const c_MatrixXf &features, LabelCompatibility*, KernelType, NormalizationType)
void setUnaryEnergy(UnaryEnergy *unary)
void setUnaryEnergy(const c_MatrixXf &unary)
void setUnaryEnergy(const c_MatrixXf &L, const c_MatrixXf &feature)

# Inference methods.
c_MatrixXf inference(int n_iterations)
# TODO: Not enabled because it would require wrapping VectorXs (note the `s`)
#c_VectorXs map(int n_iterations)

# Step-by-step inference methods.
c_MatrixXf startInference() const
void stepInference(c_MatrixXf &Q, c_MatrixXf &tmp1, c_MatrixXf &tmp2) const
#double gradient( int n_iterations, const ObjectiveFunction & objective, c_VectorXf * unary_grad, c_VectorXf * lbl_cmp_grad, c_VectorXf * kernel_grad=NULL ) const;

double klDivergence(const c_MatrixXf &Q) const

#c_VectorXf unaryParameters() const;
#void setUnaryParameters( const c_VectorXf & v );
#c_VectorXf labelCompatibilityParameters() const;
#void setLabelCompatibilityParameters( const c_VectorXf & v );
#c_VectorXf kernelParameters() const;
#void setKernelParameters( const c_VectorXf & v );


cdef extern from "densecrf/include/densecrf.h":
cdef cppclass c_DenseCRF2D "DenseCRF2D" (c_DenseCRF):
c_DenseCRF2D(int W, int H, int M) except +

void addPairwiseGaussian(float sx, float sy, LabelCompatibility*, KernelType, NormalizationType)
void addPairwiseBilateral(float sx, float sy, float sr, float sg, float sb, const unsigned char *rgbim, LabelCompatibility*, KernelType, NormalizationType)


cdef class DenseCRF:
cdef c_DenseCRF *_this
cdef int _nlabel
cdef int _nvar


cdef class DenseCRF2D(DenseCRF):
cdef c_DenseCRF2D *_this2d
cdef int _w
cdef int _h
140 changes: 140 additions & 0 deletions packages/patches/pydensecrf/pydensecrf/densecrf.pyx
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@
# distutils: language = c++
# distutils: sources = pydensecrf/densecrf/src/densecrf.cpp pydensecrf/densecrf/src/unary.cpp pydensecrf/densecrf/src/pairwise.cpp pydensecrf/densecrf/src/permutohedral.cpp pydensecrf/densecrf/src/optimization.cpp pydensecrf/densecrf/src/objective.cpp pydensecrf/densecrf/src/labelcompatibility.cpp pydensecrf/densecrf/src/util.cpp pydensecrf/densecrf/external/liblbfgs/lib/lbfgs.c
# distutils: include_dirs = pydensecrf/densecrf/include pydensecrf/densecrf/external/liblbfgs/include

from numbers import Number

import eigen
from .eigen cimport *


cdef LabelCompatibility* _labelcomp(compat) except NULL:
if isinstance(compat, Number):
return new PottsCompatibility(compat)
elif memoryview(compat).ndim == 1:
return new DiagonalCompatibility(c_vectorXf(compat))
elif memoryview(compat).ndim == 2:
return new MatrixCompatibility(c_matrixXf(compat))
else:
raise ValueError("LabelCompatibility of dimension >2 not meaningful.")
return NULL # Important for the exception(s) to propagate!


cdef class Unary:

# Because all of the APIs that take an object of this type will
# take ownership. Thus, we need to make sure not to delete this
# upon destruction.
cdef UnaryEnergy* move(self):
ptr = self.thisptr
self.thisptr = NULL
return ptr

# It might already be deleted by the library, actually.
# Yeah, pretty sure it is.
def __dealloc__(self):
del self.thisptr


cdef class ConstUnary(Unary):
def __cinit__(self, float[:,::1] u not None):
self.thisptr = new ConstUnaryEnergy(c_matrixXf(u))


cdef class LogisticUnary(Unary):
def __cinit__(self, float[:,::1] L not None, float[:,::1] f not None):
self.thisptr = new LogisticUnaryEnergy(c_matrixXf(L), c_matrixXf(f))


cdef class DenseCRF:

def __cinit__(self, int nvar, int nlabels, *_, **__):
# We need to swallow extra-arguments because superclass cinit function
# will always be called with the same params as the subclass, automatically.

# We also only want to avoid creating an object if we're just being called
# from a subclass as part of the hierarchy.
if type(self) is DenseCRF:
self._this = new c_DenseCRF(nvar, nlabels)
else:
self._this = NULL

self._nvar = nvar
self._nlabel = nlabels

def __dealloc__(self):
# Because destructors are virtual, this is enough to delete any object
# of child classes too.
if self._this:
del self._this

def addPairwiseEnergy(self, float[:,::1] features not None, compat, KernelType kernel=DIAG_KERNEL, NormalizationType normalization=NORMALIZE_SYMMETRIC):
if features.shape[1] != self._nvar:
raise ValueError("Bad shape for pairwise energy (Need (?, {}), got {})".format(self._nvar, (features.shape[0], features.shape[1])))

self._this.addPairwiseEnergy(c_matrixXf(features), _labelcomp(compat), kernel, normalization)

def setUnary(self, Unary u):
self._this.setUnaryEnergy(u.move())

def setUnaryEnergy(self, float[:,::1] u not None, float[:,::1] f = None):
if u.shape[0] != self._nlabel or u.shape[1] != self._nvar:
raise ValueError("Bad shape for unary energy (Need {}, got {})".format((self._nlabel, self._nvar), (u.shape[0], u.shape[1])))
# TODO: I don't remember the exact shape `f` should have, so I'm not putting an assertion here.
# If you get hit by a wrong shape of `f`, please open an issue with the necessary info!

if f is None:
self._this.setUnaryEnergy(c_matrixXf(u))
else:
self._this.setUnaryEnergy(c_matrixXf(u), c_matrixXf(f))

def inference(self, int niter):
return MatrixXf().wrap(self._this.inference(niter))

def startInference(self):
return MatrixXf().wrap(self._this.startInference()), MatrixXf(), MatrixXf()

def stepInference(self, MatrixXf Q, MatrixXf tmp1, MatrixXf tmp2):
self._this.stepInference(Q.m, tmp1.m, tmp2.m)

def klDivergence(self, MatrixXf Q):
return self._this.klDivergence(Q.m)


cdef class DenseCRF2D(DenseCRF):

# The same comments as in the superclass' `__cinit__` apply here.
def __cinit__(self, int w, int h, int nlabels, *_, **__):
if type(self) is DenseCRF2D:
self._this = self._this2d = new c_DenseCRF2D(w, h, nlabels)

# Unfortunately, self._this2d.W_ and .H_ are protected in C++ and thus
# we cannot access them from here for sanity-checks, so keep our own...
self._w = w
self._h = h

# Also set these for the superclass
self._nvar = w*h
self._nlabel = nlabels

def addPairwiseGaussian(self, sxy, compat, KernelType kernel=DIAG_KERNEL, NormalizationType normalization=NORMALIZE_SYMMETRIC):
if isinstance(sxy, Number):
sxy = (sxy, sxy)

self._this2d.addPairwiseGaussian(sxy[0], sxy[1], _labelcomp(compat), kernel, normalization)

def addPairwiseBilateral(self, sxy, srgb, unsigned char[:,:,::1] rgbim not None, compat, KernelType kernel=DIAG_KERNEL, NormalizationType normalization=NORMALIZE_SYMMETRIC):
if isinstance(sxy, Number):
sxy = (sxy, sxy)

if isinstance(srgb, Number):
srgb = (srgb, srgb, srgb)

if rgbim.shape[0] != self._h or rgbim.shape[1] != self._w:
raise ValueError("Bad shape for pairwise bilateral (Need {}, got {})".format((self._h, self._w, 3), rgbim.shape))
if rgbim.shape[2] != 3:
raise ValueError("addPairwiseBilateral only works for RGB images. For other types, use `utils.create_pairwise_bilateral` to construct your own pairwise energy and add it through `addPairwiseEnergy`.")

self._this2d.addPairwiseBilateral(
sxy[0], sxy[1], srgb[0], srgb[1], srgb[2], &rgbim[0,0,0], _labelcomp(compat), kernel, normalization
)
44 changes: 44 additions & 0 deletions packages/patches/pydensecrf/setup.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
# coding: UTF-8
from setuptools import setup

# TODO:
# - Wrap learning.
# - Make LabelCompatibility, UnaryEnergy, PairwisePotential extensible? (Maybe overkill?)


# If Cython is available, build using Cython.
# Otherwise, use the pre-built (by someone who has Cython, i.e. me) wrapper `.cpp` files.
try:
from Cython.Build import cythonize
ext_modules = cythonize(['pydensecrf/eigen.pyx'])
ext_modules = cythonize(['pydensecrf/densecrf.pyx'])
except ImportError:
from setuptools.extension import Extension
ext_modules = [
Extension("pydensecrf/eigen", ["pydensecrf/eigen.cpp", "pydensecrf/eigen_impl.cpp"], language="c++", include_dirs=["pydensecrf/densecrf/include"]),
Extension("pydensecrf/densecrf", ["pydensecrf/densecrf.cpp", "pydensecrf/densecrf/src/densecrf.cpp", "pydensecrf/densecrf/src/unary.cpp", "pydensecrf/densecrf/src/pairwise.cpp", "pydensecrf/densecrf/src/permutohedral.cpp", "pydensecrf/densecrf/src/optimization.cpp", "pydensecrf/densecrf/src/objective.cpp", "pydensecrf/densecrf/src/labelcompatibility.cpp", "pydensecrf/densecrf/src/util.cpp", "pydensecrf/densecrf/external/liblbfgs/lib/lbfgs.c"], language="c++", include_dirs=["pydensecrf/densecrf/include", "pydensecrf/densecrf/external/liblbfgs/include"]),
]

setup(
name="pydensecrf",
version="1.0rc2",
description="A python interface to Philipp Krähenbühl's fully-connected (dense) CRF code.",
long_description="See the README.md at http://github.com/lucasb-eyer/pydensecrf",
author="Lucas Beyer",
author_email="lucasb.eyer.be@gmail.com",
url="http://github.com/lucasb-eyer/pydensecrf",
ext_modules=ext_modules,
packages=["pydensecrf"],
setup_requires=['cython>=0.22'],
classifiers=[
"Intended Audience :: Developers",
"License :: OSI Approved :: MIT License",
"Development Status :: 5 - Production/Stable",
"Programming Language :: C++",
"Programming Language :: Python",
"Operating System :: POSIX :: Linux",
"Topic :: Software Development :: Libraries",
"Topic :: Scientific/Engineering :: Image Recognition",
"Topic :: Scientific/Engineering :: Artificial Intelligence",
],
)

0 comments on commit c248dd9

Please sign in to comment.