Skip to content

Commit

Permalink
.
Browse files Browse the repository at this point in the history
  • Loading branch information
dtschump committed Aug 28, 2024
2 parents 64be617 + d486d70 commit afaaabb
Show file tree
Hide file tree
Showing 2 changed files with 83 additions and 83 deletions.
163 changes: 81 additions & 82 deletions CImg.h
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@

// Set version number of the library.
#ifndef cimg_version
#define cimg_version 340
#define cimg_version 341

/*-----------------------------------------------------------
#
Expand Down Expand Up @@ -170,6 +170,7 @@
#include <sys/types.h>
#include <sys/time.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <dirent.h>
#include <fnmatch.h>
Expand Down Expand Up @@ -7568,6 +7569,10 @@ namespace cimg_library {
inline const char *powershell_path(const char *const user_path=0, const bool reinit_path=false);
#endif

#if cimg_OS==1
inline bool posix_searchpath(const char *file);
#endif

//! Split filename into two C-strings \c body and \c extension.
/**
filename and body must not overlap!
Expand Down Expand Up @@ -32439,109 +32444,101 @@ namespace cimg_library {
"project_matrix(): Specified dictionary (%u,%u,%u,%u) has an invalid size.",
cimg_instance,
dictionary._width,dictionary._height,dictionary._depth,dictionary._spectrum);

if (!method) return get_solve(dictionary);
CImg<Tfloat> W(_width,dictionary._width,1,1,0);

// Compute dictionary norm and normalize it.
CImg<Tfloat> D(dictionary,false), Dnorm(D._width);
cimg_pragma_openmp(parallel for cimg_openmp_if(_width>=2 && _width*_height>=32))
cimg_forX(Dnorm,d) {
// Compute norm of dictionary atoms.
CImg<Tfloat> dictionary_norm(dictionary._width);
cimg_pragma_openmp(parallel for
cimg_openmp_if(dictionary._width>=2 && dictionary._width*dictionary._height>=32))
cimg_forX(dictionary_norm,atom) {
Tfloat norm = 0;
cimg_forY(D,y) norm+=cimg::sqr(D(d,y));
Dnorm[d] = std::max((Tfloat)1e-8,std::sqrt(norm));
cimg_forY(dictionary,s) norm+=cimg::sqr(dictionary(atom,s));
dictionary_norm[atom] = std::max((Tfloat)1e-8,std::sqrt(norm));
}
cimg_forXY(D,d,y) D(d,y)/=Dnorm[d];

// Matching pursuit.
CImg<Tfloat> weights(_width,dictionary._width,1,1,0);
const unsigned int proj_step = method<3?1:method - 2;
bool is_orthoproj = false;

cimg_pragma_openmp(parallel for cimg_openmp_if(_width>=2 && _width*_height>=32))
cimg_forX(*this,x) {
CImg<Tfloat> S = get_column(x);
const CImg<Tfloat> S0 = method<2?CImg<Tfloat>():S;
Tfloat residual = S.magnitude(2)/S._height;
const unsigned int nmax = max_iter?max_iter:D._width;

for (unsigned int n = 0; n<nmax && residual>max_residual; ++n) {

// Find best matching column in D.
int dmax = 0;
Tfloat absdotmax = 0, dotmax = 0;
cimg_pragma_openmp(parallel for cimg_openmp_if(D._width>=2 && D._width*D._height>=32))
cimg_forX(D,d) {
Tfloat _dot = 0;
cimg_forY(D,y) _dot+=S[y]*D(d,y);
Tfloat absdot = cimg::abs(_dot);
cimg_forX(*this,signal) {
CImg<Tfloat> R = get_column(signal); // Residual signal
const CImg<Tfloat> R0 = method<2?CImg<Tfloat>():R;
Tfloat residual = R.magnitude(2)/R._height;
const unsigned int _max_iter = max_iter?max_iter:dictionary._width;

for (unsigned int iter = 0; iter<_max_iter && residual>max_residual; ++iter) {

// Find best matching column from dictionary D.
int max_atom = 0;
Tfloat max_absdot = 0, max_dot = 0;
cimg_pragma_openmp(parallel for
cimg_openmp_if(dictionary._width>=2 && dictionary._width*dictionary._height>=32))
cimg_forX(dictionary,atom) {
Tfloat dot = 0;
cimg_forY(R,s) dot+=R[s]*dictionary(atom,s);
dot/=dictionary_norm[atom];
const Tfloat absdot = cimg::abs(dot);
cimg_pragma_openmp(critical(get_project_matrix)) {
if (absdot>absdotmax) {
absdotmax = absdot;
dotmax = _dot;
dmax = d;
}
if (absdot>max_absdot) { max_atom = atom; max_dot = dot; max_absdot = absdot; }
}
}

if (!n || method<3 || n%proj_step) {
if (!iter || method<3 || iter%proj_step) {
// Matching Pursuit: Subtract component to signal.
W(x,dmax)+=dotmax;
max_dot/=dictionary_norm[max_atom];
weights(signal,max_atom)+=max_dot;
residual = 0;
cimg_forY(S,y) {
S[y]-=dotmax*D(dmax,y);
residual+=cimg::sqr(S[y]);
}
residual = std::sqrt(residual)/S._height;
cimg_forY(R,s) { R[s]-=max_dot*dictionary(max_atom,s); residual+=cimg::sqr(R[s]); }
residual = std::sqrt(residual)/R._height;
is_orthoproj = false;

} else {
// Orthogonal Matching Pursuit: Orthogonal projection step.
W(x,dmax) = 1; // Used as a marker only.
unsigned int nbW = 0;
cimg_forY(W,d) if (W(x,d)) ++nbW;
CImg<Tfloat> sD(nbW,D._height);
CImg<uintT> inds(nbW);
int sd = 0;
cimg_forY(W,d) if (W(x,d)) {
cimg_forY(sD,y) sD(sd,y) = D(d,y);
inds[sd++] = d;
}
S0.get_solve(sD).move_to(sD); // sD is now a one-column vector of weights

// Recompute residual signal.
S = S0;
cimg_forY(sD,k) {
const Tfloat weight = sD[k];
const unsigned int ind = inds[k];
W(x,ind) = weight;
cimg_forY(S,y) S[y]-=weight*D(ind,y);
}
residual = S.magnitude(2)/S._height;
weights(signal,max_atom) = 1; // Use only as a marker
unsigned int nb_weights = 0;
cimg_forY(weights,atom) if (weights(signal,atom)) ++nb_weights;
CImg<Tfloat> sub_dictionary(nb_weights,dictionary._height);
CImg<uintT> sub_atoms(nb_weights);
int ind = 0;
cimg_forY(weights,atom) if (weights(signal,atom)) {
cimg_forY(sub_dictionary,s) sub_dictionary(ind,s) = dictionary(atom,s);
sub_atoms[ind++] = atom;
}
const CImg<Tfloat> sub_weights = R0.get_solve(sub_dictionary);

// Recompute residual signal according to the projected weights.
R = R0;
cimg_forY(sub_weights,sub_atom) {
const Tfloat weight = sub_weights[sub_atom];
const unsigned int atom = sub_atoms[sub_atom];
weights(signal,atom) = weight;
cimg_forY(R,s) R[s]-=weight*dictionary(atom,s);
}
residual = R.magnitude(2)/R._height;
is_orthoproj = true;
}
}

// Perform last orthoprojection step if needed.
if (method>=2 && !is_orthoproj) {
unsigned int nbW = 0;
cimg_forY(W,d) if (W(x,d)) ++nbW;
if (nbW) { // Avoid degenerated case where 0 coefs are used
CImg<Tfloat> sD(nbW,D._height);
CImg<uintT> inds(nbW);
int sd = 0;
cimg_forY(W,d) if (W(x,d)) {
cimg_forY(sD,y) sD(sd,y) = D(d,y);
inds[sd++] = d;
unsigned int nb_weights = 0;
cimg_forY(weights,atom) if (weights(signal,atom)) ++nb_weights;
if (nb_weights) { // Avoid degenerated case where 0 coefs are used
CImg<Tfloat> sub_dictionary(nb_weights,dictionary._height);
CImg<uintT> sub_atoms(nb_weights);
int ind = 0;
cimg_forY(weights,atom) if (weights(signal,atom)) {
cimg_forY(sub_dictionary,s) sub_dictionary(ind,s) = dictionary(atom,s);
sub_atoms[ind++] = atom;
}
S0.get_solve(sD).move_to(sD);
cimg_forY(sD,k) W(x,inds[k]) = sD[k];
const CImg<Tfloat> sub_weights = R0.get_solve(sub_dictionary);
cimg_forY(sub_weights,sub_atom) weights(signal,sub_atoms[sub_atom]) = sub_weights[sub_atom];
}
}
}

// Normalize resulting coefficients according to initial (non-normalized) dictionary.
cimg_forXY(W,x,y) W(x,y)/=Dnorm[y];
return W;
return weights;
}

//! Compute minimal path in a graph, using the Dijkstra algorithm.
Expand Down Expand Up @@ -58144,7 +58141,7 @@ namespace cimg_library {
std::FILE *file = 0;
const CImg<charT> s_filename = CImg<charT>::string(filename)._system_strescape();
#if cimg_OS==1
if (!cimg::system("which gm")) {
if (cimg::posix_searchpath("gm")) {
cimg_snprintf(command,command._width,"%s convert \"%s\" %s:-",
cimg::graphicsmagick_path(),
s_filename.data(),
Expand Down Expand Up @@ -58284,10 +58281,11 @@ namespace cimg_library {
CImg<charT> command(1024), filename_tmp(256);
std::FILE *file = 0;
const CImg<charT> s_filename = CImg<charT>::string(filename)._system_strescape();
const char *magick_path = cimg::imagemagick_path();
#if cimg_OS==1
if (!cimg::system("which convert")) {
if (cimg::posix_searchpath("magick") || cimg::posix_searchpath("convert")) {
cimg_snprintf(command,command._width,"%s%s \"%s\" %s:-",
cimg::imagemagick_path(),
magick_path,
!cimg::strcasecmp(cimg::split_filename(filename),"pdf")?" -density 400x400":"",
s_filename.data(),
#ifdef cimg_use_png
Expand Down Expand Up @@ -58334,11 +58332,11 @@ namespace cimg_library {
if ((file=cimg::std_fopen(filename_tmp,"rb"))!=0) cimg::fclose(file);
} while (file);
cimg_snprintf(command,command._width,"\"%s\"%s \"%s\" \"%s\"",
cimg::imagemagick_path(),
magick_path,
!cimg::strcasecmp(cimg::split_filename(filename),"pdf")?" -density 400x400":"",
s_filename.data(),
CImg<charT>::string(filename_tmp)._system_strescape().data());
cimg::system(command,cimg::imagemagick_path());
cimg::system(command,magick_path);
if (!(file=cimg::std_fopen(filename_tmp,"rb"))) {
cimg::fclose(cimg::fopen(filename,"r"));
throw CImgIOException(_cimg_instance
Expand Down Expand Up @@ -62062,11 +62060,12 @@ namespace cimg_library {
#else
save_pnm(filename_tmp);
#endif
const char *magick_path = cimg::imagemagick_path();
cimg_snprintf(command,command._width,"\"%s\" -quality %u \"%s\" \"%s\"",
cimg::imagemagick_path(),quality,
magick_path,quality,
CImg<charT>::string(filename_tmp)._system_strescape().data(),
CImg<charT>::string(filename)._system_strescape().data());
cimg::system(command,cimg::imagemagick_path());
cimg::system(command,magick_path);
file = cimg::std_fopen(filename,"rb");
if (!file)
throw CImgIOException(_cimg_instance
Expand Down Expand Up @@ -67453,7 +67452,7 @@ namespace cimg_library {
std::memcpy(buf,p,z - p);
buf[z - p] = '/';
std::memcpy(buf + (z - p) + (z>p),file,file_len + 1);
if (cimg::is_file(buf)) { delete[] buf; return true; }
if (cimg::is_file(buf) && faccessat(AT_FDCWD, buf, X_OK, AT_EACCESS) == 0) { delete[] buf; return true; }
if (!*z++) break;
p = z;
}
Expand Down
3 changes: 2 additions & 1 deletion plugins/jpeg_buffer.h
Original file line number Diff line number Diff line change
Expand Up @@ -234,7 +234,8 @@ static CImg get_load_jpeg_buffer(const JOCTET *const buffer, const unsigned buff
jpeg_start_decompress(&cinfo);

const unsigned int row_stride = cinfo.output_width * cinfo.output_components;
JOCTET *buf = new JOCTET[cinfo.output_width*cinfo.output_height*cinfo.output_components];
const size_t siz = safe_size(cinfo.output_width,cinfo.output_height,1,cinfo.output_components);
JOCTET *buf = new JOCTET[siz];
const JOCTET *buf2 = buf;
JSAMPROW row_pointer[1];
while (cinfo.output_scanline < cinfo.output_height) {
Expand Down

0 comments on commit afaaabb

Please sign in to comment.