Skip to content

Commit

Permalink
i.svm: Add LIBSVM-based image classification (#2189)
Browse files Browse the repository at this point in the history
Two modules – i.svm.train and i.svm.predict – provide a supervised raster imagery classification workflow. Both modules utilize LIBSVM to perform actual classification. Modules are designed to mimic existing classification modules e.g. by providing similar parameter names.

Thanks to @wenzeslaus and @nilason for helpful feedback.
  • Loading branch information
marisn authored Jan 9, 2024
1 parent e6a3771 commit fdc72d1
Show file tree
Hide file tree
Showing 23 changed files with 2,524 additions and 7 deletions.
201 changes: 201 additions & 0 deletions configure
Original file line number Diff line number Diff line change
Expand Up @@ -679,6 +679,9 @@ CAIROLIB
CAIROINC
CAIRO_HAS_XRENDER_SURFACE
CAIRO_HAS_XRENDER
USE_LIBSVM
LIBSVM_LIB
LIBSVM_INC
LAPACKINC
LAPACKLIB
BLASINC
Expand Down Expand Up @@ -902,6 +905,7 @@ with_odbc
with_fftw
with_blas
with_lapack
with_libsvm
with_cairo
with_freetype
with_nls
Expand Down Expand Up @@ -948,6 +952,8 @@ with_blas_includes
with_blas_libs
with_lapack_includes
with_lapack_libs
with_libsvm_includes
with_libsvm_libs
with_cairo_includes
with_cairo_libs
with_cairo_ldflags
Expand Down Expand Up @@ -1634,6 +1640,7 @@ Optional Packages:
--with-fftw support FFTW functionality (default: yes)
--with-blas support BLAS functionality (default: no)
--with-lapack support LAPACK functionality (default: no)
--with-libsvm support LIBSVM functionality (default: no)
--with-cairo support Cairo functionality (default: yes)
--with-freetype support FreeType functionality (default: yes)
--with-nls support NLS functionality (default: no)
Expand Down Expand Up @@ -1709,6 +1716,9 @@ Optional Packages:
--with-lapack-includes=DIRS
LAPACK include files are in DIRS
--with-lapack-libs=DIRS LAPACK library files are in DIRS
--with-libsvm-includes=DIRS
LIBSVM include files are in DIRS
--with-libsvm-libs=DIRS LIBSVM library files are in DIRS
--with-cairo-includes=DIRS
cairo include files are in DIRS
--with-cairo-libs=DIRS cairo library files are in DIRS
Expand Down Expand Up @@ -5468,6 +5478,17 @@ fi



# Check whether --with-libsvm was given.
if test ${with_libsvm+y}
then :
withval=$with_libsvm;
else $as_nop
with_libsvm=no
fi




# Check whether --with-cairo was given.
if test ${with_cairo+y}
then :
Expand Down Expand Up @@ -5921,6 +5942,25 @@ fi



# Check whether --with-libsvm-includes was given.
if test ${with_libsvm_includes+y}
then :
withval=$with_libsvm_includes;
fi




# Check whether --with-libsvm-libs was given.
if test ${with_libsvm_libs+y}
then :
withval=$with_libsvm_libs;
fi





# Check whether --with-cairo-includes was given.
if test ${with_cairo_includes+y}
then :
Expand Down Expand Up @@ -14519,6 +14559,165 @@ fi # $USE_BLAS

# Done checking LAPACK

# libsvm option
LIBSVM_INC=
LIBSVM_LIB=
USE_LIBSVM=


{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether to use LIBSVM" >&5
printf %s "checking whether to use LIBSVM... " >&6; }
{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: \"$with_libsvm\"" >&5
printf "%s\n" "\"$with_libsvm\"" >&6; }
case "$with_libsvm" in
"no") USE_LIBSVM= ;;
"yes") USE_LIBSVM="1" ;;
*) as_fn_error $? "*** You must answer yes or no." "$LINENO" 5 ;;
esac



if test -n "$USE_LIBSVM"; then

{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for location of LIBSVM includes" >&5
printf %s "checking for location of LIBSVM includes... " >&6; }
case "$with_libsvm_includes" in
y | ye | yes | n | no)
as_fn_error $? "*** You must supply a directory to --with-libsvm-includes." "$LINENO" 5
;;
esac
{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $with_libsvm_includes" >&5
printf "%s\n" "$with_libsvm_includes" >&6; }

if test -n "$with_libsvm_includes" ; then
for dir in $with_libsvm_includes; do
if test -d "$dir"; then
LIBSVM_INC="$LIBSVM_INC -I$dir"
else
as_fn_error $? "*** LIBSVM includes directory $dir does not exist." "$LINENO" 5
fi
done
fi


ac_save_cppflags="$CPPFLAGS"
CPPFLAGS="$LIBSVM_INC $CPPFLAGS"
for ac_header in svm.h
do :
ac_fn_c_check_header_compile "$LINENO" "svm.h" "ac_cv_header_svm_h" "$ac_includes_default"
if test "x$ac_cv_header_svm_h" = xyes
then :
printf "%s\n" "#define HAVE_SVM_H 1" >>confdefs.h

else $as_nop

ac_save_cppflags="$CPPFLAGS"
CPPFLAGS="$LIBSVM_INC $CPPFLAGS"
for ac_header in libsvm/svm.h
do :
ac_fn_c_check_header_compile "$LINENO" "libsvm/svm.h" "ac_cv_header_libsvm_svm_h" "$ac_includes_default"
if test "x$ac_cv_header_libsvm_svm_h" = xyes
then :
printf "%s\n" "#define HAVE_LIBSVM_SVM_H 1" >>confdefs.h

else $as_nop

as_fn_error $? "*** Unable to locate LIBSVM includes." "$LINENO" 5

fi

done
CPPFLAGS=$ac_save_cppflags


fi

done
CPPFLAGS=$ac_save_cppflags


{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for location of libsvm library" >&5
printf %s "checking for location of libsvm library... " >&6; }
case "$with_libsvm_libs" in
y | ye | yes | n | no)
as_fn_error $? "*** You must supply a directory to --with-libsvm-libs." "$LINENO" 5
;;
esac
{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $with_libsvm_libs" >&5
printf "%s\n" "$with_libsvm_libs" >&6; }

if test -n "$with_libsvm_libs"; then
for dir in $with_libsvm_libs; do
if test -d "$dir"; then
LIBSVM_LIB="$LIBSVM_LIB -L$dir"
else
as_fn_error $? "*** libsvm library directory $dir does not exist." "$LINENO" 5
fi
done
fi


ac_save_ldflags="$LDFLAGS"
LDFLAGS="$LIBSVM_LIB $LDFLAGS"


{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for svm_load_model in -lsvm" >&5
printf %s "checking for svm_load_model in -lsvm... " >&6; }

ac_check_lib_save_LIBS=$LIBS
LIBS="-lsvm $LIBS"
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
/* Override any GCC internal prototype to avoid an error.
Use char because int might match the return type of a GCC
builtin and then its argument prototype would still apply. */
char svm_load_model ();
int
main (void)
{
return svm_load_model ();
;
return 0;
}
_ACEOF
if ac_fn_c_try_link "$LINENO"
then :
ac_cv_lib_svm_svm_load_model=yes
else $as_nop
ac_cv_lib_svm_svm_load_model=no
fi
rm -f core conftest.err conftest.$ac_objext conftest.beam \
conftest$ac_exeext conftest.$ac_ext
LIBS=$ac_check_lib_save_LIBS
{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_svm_svm_load_model" >&5
printf "%s\n" "$ac_cv_lib_svm_svm_load_model" >&6; }
if test "x$ac_cv_lib_svm_svm_load_model" = xyes
then :
LIBSVM_LIB="$LIBSVM_LIB -lsvm "
else $as_nop

LDFLAGS=${ac_save_ldflags}

as_fn_error $? "*** Unable to locate LIBSVM library." "$LINENO" 5


fi



LDFLAGS=${ac_save_ldflags}


printf "%s\n" "#define HAVE_LIBSVM 1" >>confdefs.h

fi




# Done with LIBSVM

# Enable Cairo display driver option


Expand Down Expand Up @@ -17436,6 +17635,8 @@ echo " Large File support (LFS): `if test -n "${USE_LARGEFILES}" ; then echo
echo " libLAS support: `if test -n "${USE_LIBLAS}" ; then echo yes ; else echo no ; fi`"
echo " LIBSVM support: `if test -n "${USE_LIBSVM}" ; then echo yes ; else echo no ; fi`"
echo " MySQL support: `if test -n "${USE_MYSQL}" ; then echo yes ; else echo no ; fi`"
echo " NetCDF support: `if test -n "${USE_NETCDF}" ; then echo yes ; else echo no ; fi`"
Expand Down
27 changes: 27 additions & 0 deletions configure.ac
Original file line number Diff line number Diff line change
Expand Up @@ -296,6 +296,7 @@ LOC_ARG_WITH(odbc, ODBC, no)
LOC_ARG_WITH(fftw, FFTW)
LOC_ARG_WITH(blas, BLAS, no)
LOC_ARG_WITH(lapack, LAPACK, no)
LOC_ARG_WITH(libsvm, LIBSVM, no)
LOC_ARG_WITH(cairo, Cairo)
LOC_ARG_WITH(freetype, FreeType)
LOC_ARG_WITH(nls, NLS, no)
Expand Down Expand Up @@ -385,6 +386,9 @@ LOC_ARG_WITH_LIB(blas, BLAS)
LOC_ARG_WITH_INC(lapack, LAPACK)
LOC_ARG_WITH_LIB(lapack, LAPACK)

LOC_ARG_WITH_INC(libsvm, LIBSVM)
LOC_ARG_WITH_LIB(libsvm, LIBSVM)

LOC_ARG_WITH_INC(cairo, cairo)
LOC_ARG_WITH_LIB(cairo, cairo)
LOC_ARG_WITH_LDFLAGS(cairo, cairo)
Expand Down Expand Up @@ -1696,6 +1700,28 @@ AC_SUBST(LAPACKINC)

# Done checking LAPACK

# libsvm option
LIBSVM_INC=
LIBSVM_LIB=
USE_LIBSVM=

LOC_CHECK_USE(libsvm,LIBSVM,USE_LIBSVM)

if test -n "$USE_LIBSVM"; then
LOC_CHECK_INC_PATH(libsvm,LIBSVM,LIBSVM_INC)
LOC_CHECK_INCLUDES(svm.h,LIBSVM,$LIBSVM_INC, [
LOC_CHECK_INCLUDES(libsvm/svm.h,LIBSVM,$LIBSVM_INC)
])
LOC_CHECK_LIB_PATH(libsvm,libsvm,LIBSVM_LIB)
LOC_CHECK_LIBS(svm,svm_load_model,LIBSVM,$LIBSVM_LIB,LIBSVM_LIB,,,)
AC_DEFINE(HAVE_LIBSVM, 1, [Define to 1 if using LIBSVM.])
fi

AC_SUBST(LIBSVM_INC)
AC_SUBST(LIBSVM_LIB)
AC_SUBST(USE_LIBSVM)
# Done with LIBSVM

# Enable Cairo display driver option

LOC_CHECK_USE(cairo,Cairo,USE_CAIRO)
Expand Down Expand Up @@ -2022,6 +2048,7 @@ LOC_MSG_USE(GEOS support,USE_GEOS)
LOC_MSG_USE(LAPACK support,USE_LAPACK)
LOC_MSG_USE(Large File support (LFS), USE_LARGEFILES)
LOC_MSG_USE(libLAS support,USE_LIBLAS)
LOC_MSG_USE(LIBSVM support,USE_LIBSVM)
LOC_MSG_USE(MySQL support,USE_MYSQL)
LOC_MSG_USE(NetCDF support,USE_NETCDF)
LOC_MSG_USE(NLS support,USE_NLS)
Expand Down
7 changes: 5 additions & 2 deletions gui/wxpython/gui_core/gselect.py
Original file line number Diff line number Diff line change
Expand Up @@ -3096,7 +3096,7 @@ def __init__(
def UpdateItems(self, element):
"""Update list of signature files for given element
:param str element: signatures/sig or signatures/sigset
:param str element: signatures/sig, signatures/sigset or signatures/libsvm
"""
items = []
if self.mapsets:
Expand All @@ -3120,6 +3120,7 @@ def _append_mapset_signatures(self, mapset, element, items):
from grass.lib.imagery import (
I_SIGFILE_TYPE_SIG,
I_SIGFILE_TYPE_SIGSET,
I_SIGFILE_TYPE_LIBSVM,
I_signatures_list_by_type,
I_free_signatures_list,
)
Expand All @@ -3133,6 +3134,8 @@ def _append_mapset_signatures(self, mapset, element, items):
sig_type = I_SIGFILE_TYPE_SIG
elif element == "signatures/sigset":
sig_type = I_SIGFILE_TYPE_SIGSET
elif element == "signatures/libsvm":
sig_type = I_SIGFILE_TYPE_LIBSVM
else:
return
list_ptr = ctypes.POINTER(ctypes.c_char_p)
Expand All @@ -3151,7 +3154,7 @@ def __init__(
):
super().__init__(parent, id, size=size, **kwargs)
self.SetName("SignatureTypeSelect")
self.SetItems(["sig", "sigset"])
self.SetItems(["sig", "sigset", "libsvm"])


class SeparatorSelect(wx.ComboBox):
Expand Down
7 changes: 7 additions & 0 deletions gui/wxpython/xml/toolboxes.xml
Original file line number Diff line number Diff line change
Expand Up @@ -1559,6 +1559,13 @@
<label>Sequential maximum a posteriori classification (SMAP)</label>
</module-item>
<separator/>
<module-item name="i.svm.train">
<label>Input for supervised SVM</label>
</module-item>
<module-item name="i.svm.predict">
<label>Support Vector Machines classification (SVM)</label>
</module-item>
<separator/>
<module-item name="i.signatures">
<label>Manage signature files</label>
</module-item>
Expand Down
2 changes: 2 additions & 0 deletions imagery/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,8 @@ SUBDIRS = \
i.segment \
i.signatures \
i.smap \
i.svm.predict \
i.svm.train \
i.target \
i.topo.corr \
i.pca \
Expand Down
Loading

0 comments on commit fdc72d1

Please sign in to comment.