FloatImg/lib/fimg-math.c

438 lines
10 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*
* fimg-math.c
*
*
*/
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <unistd.h>
#include <string.h>
#include <float.h> /* for FLT_MAX */
#include <math.h>
#include "../floatimg.h"
extern int verbosity; /* must be declared around main() */
/* ---------------------------------------------------------------- */
/* nouveau 27 fevrier 2022 */
float fimg_get_plane_maxvalue(FloatImg *psrc, char plane)
{
float *ptrplane;
float maxval;
int area, foo;
#if DEBUG_LEVEL
fprintf(stderr, ">>> %s ( %p '%c' )\n", __func__, psrc, plane);
#endif
switch (plane) {
case 'r': case 'R':
ptrplane = psrc->R; break;
case 'g': case 'G':
ptrplane = psrc->G; break;
case 'b': case 'B':
ptrplane = psrc->B; break;
case 'a': case 'A':
ptrplane = psrc->A; break;
default:
fprintf(stderr, "%s: plane error\n", __func__);
abort(); break;
}
area = psrc->width * psrc->height;
maxval = 0.0;
for (foo=0; foo<area; foo++) {
if (ptrplane[foo] > maxval) maxval = ptrplane[foo];
}
return maxval;
}
/* ---------------------------------------------------------------- */
float fimg_get_maxvalue(FloatImg *head)
{
float maxval;
int foo, surface;
if (head->type != FIMG_TYPE_RGB && head->type != FIMG_TYPE_GRAY) {
fprintf(stderr, "%s : type %d invalide\n",
__func__, head->type);
return nanf("wtf ?");
}
maxval = 0.0; /* no negative values allowed */
surface = head->width*head->height;
switch (head->type) {
case FIMG_TYPE_RGB:
for (foo=0; foo<surface; foo++) {
if (head->R[foo] > maxval) maxval = head->R[foo];
if (head->G[foo] > maxval) maxval = head->G[foo];
if (head->B[foo] > maxval) maxval = head->B[foo];
}
break;
case FIMG_TYPE_GRAY:
for (foo=0; foo<surface; foo++) {
if (head->R[foo] > maxval) maxval = head->R[foo];
}
break;
}
return maxval;
}
/* ---------------------------------------------------------------- */
/*
* mmval[0] <- min(R) mmval[1] <- max(R)
*/
int fimg_get_minmax_rgb(FloatImg *head, float mmvals[6])
{
int idx, surface;
float fval;
if (head->type != FIMG_TYPE_RGB) {
fprintf(stderr, "%s : type %d invalide\n",
__func__, head->type);
return -2;
}
surface = head->width * head->height;
mmvals[0] = FLT_MAX; mmvals[1] = -FLT_MAX;
mmvals[2] = FLT_MAX; mmvals[3] = -FLT_MAX;
mmvals[4] = FLT_MAX; mmvals[5] = -FLT_MAX;
for (idx=0; idx<surface; idx++) {
fval = head->R[idx];
if (fval < mmvals[0]) mmvals[0] = fval;
else if (fval > mmvals[1]) mmvals[1] = fval;
fval = head->G[idx];
if (fval < mmvals[2]) mmvals[2] = fval;
else if (fval > mmvals[3]) mmvals[3] = fval;
fval = head->B[idx];
if (fval < mmvals[4]) mmvals[4] = fval;
else if (fval > mmvals[5]) mmvals[5] = fval;
}
return 0;
}
/* ---------------------------------------------------------------- */
/* new: Fri Oct 6 19:51:28 UTC 2023
*
* can compute the maxima of a lot of pictures...
*/
int fimg_max_of_max(FloatImg *img, float maxes[3])
{
float localmax[3];
int idx, surface;
float fval;
localmax[0] = localmax[1] = localmax[2] = -1e9;
surface = img->width * img->height;
for (idx=0; idx<surface; idx++) {
fval = img->R[idx];
if (fval > localmax[0]) localmax[0] = fval;
fval = img->G[idx];
if (fval > localmax[1]) localmax[1] = fval;
fval = img->B[idx];
if (fval > localmax[2]) localmax[2] = fval;
}
if (localmax[0] > maxes[0]) maxes[0] = localmax[0];
if (localmax[1] > maxes[1]) maxes[1] = localmax[1];
if (localmax[2] > maxes[2]) maxes[2] = localmax[2];
return 0;
}
/* ---------------------------------------------------------------- */
int fimg_meanvalues(FloatImg *head, float means[4])
{
int idx, surface;
double accus[4];
surface = head->width * head->height;
if (surface < 1) return -1;
memset(accus, 0, 4*sizeof(double));
for (idx=0; idx<surface; idx++) {
accus[0] += (double)head->R[idx];
if (head->type > 2) { /* WTF ? */
accus[1] += (double)head->G[idx];
accus[2] += (double)head->B[idx];
}
}
for (idx=0; idx<4; idx++) {
means[idx] = (float)(accus[idx]/(double)surface);
}
return 0;
}
/* ---------------------------------------------------------------- */
/* d'apres Wikipedia Fr :
| c = 0
| s = x1
| pour j de 2 à n
| s = s+xj
| c = c+(j xj s)2/(j(j1))
| renvoyer c/n
Mais c,a ne semble pas etre la bonne methode. Il faut aller voir :
https://en.wikipedia.org/wiki/Algorithms_for_calculating_variance
*/
/* ---------------------------------------------------------------- */
/*
* more elaborate functions are in fimg-2gray.c
*/
int fimg_to_gray(FloatImg *head)
{
float add;
int foo;
if (head->type != FIMG_TYPE_RGB) {
fprintf(stderr, "%s : type %d invalide\n",
__func__, head->type);
return -3;
}
for (foo=0; foo<(head->width*head->height); foo++) {
add = head->R[foo] + head->G[foo] + head->B[foo];
head->R[foo] = head->G[foo] = head->B[foo] = add / 3.0;
}
return 0;
}
/* ---------------------------------------------------------------- */
int fimg_add_cste(FloatImg *fi, float value)
{
int nbre, idx;
if (fi->type != FIMG_TYPE_RGB) {
fprintf(stderr, "%s : type %d invalide\n",
__func__, fi->type);
return -44;
}
nbre = fi->width * fi->height ;
#if DEBUG_LEVEL
fprintf(stderr, "%s, nbre is %d\n", __func__, nbre);
#endif
for (idx=0; idx<nbre; idx++) {
fi->R[idx] += value;
fi->G[idx] += value;
fi->B[idx] += value;
}
return 0;
}
/* ---------------------------------------------------------------- */
long fimg_count_negativ(FloatImg *fi)
{
int nbre, idx;
long count;
if (fi->type != FIMG_TYPE_RGB) {
fprintf(stderr, "%s : type %d invalide\n",
__func__, fi->type);
return -1;
}
nbre = fi->width * fi->height;
count = 0;
for (idx=0; idx<nbre; idx++) {
if (fi->R[idx] < 0.0) count++;
if (fi->G[idx] < 0.0) count++;
if (fi->B[idx] < 0.0) count++;
}
return count;
}
/* ---------------------------------------------------------------- */
/* nouveau 29 fevrier 2020 */
long fimg_clamp_negativ(FloatImg *fi)
{
int nbre, idx;
long count;
if (fi->type != FIMG_TYPE_RGB) {
fprintf(stderr, "%s : type %d invalide\n",
__func__, fi->type);
return -1;
}
nbre = fi->width * fi->height;
count = 0;
for (idx=0; idx<nbre; idx++) {
if (fi->R[idx] < 0.0) {
fi->R[idx] = 0.0; count++;
}
if (fi->G[idx] < 0.0) {
fi->G[idx] = 0.0; count++;
}
if (fi->B[idx] < 0.0) {
fi->B[idx] = 0.0; count++;
}
}
/* WTF 12 avril 2020, valgrind me cause mal ?
==28943== Conditional jump or move depends on uninitialised value(s)
==28943== at 0x4045E9: fimg_clamp_negativ (fimg-math.c:208)
==28943== by 0x4018C9: essai_filtrage_3x3 (t.c:128)
==28943== by 0x4024D5: main (t.c:444)
==28943== Uninitialised value was created by a heap allocation
==28943== at 0x483577F: malloc (vg_replace_malloc.c:299)
==28943== by 0x40284D: fimg_create (fimg-core.c:107)
==28943== by 0x402AB3: fimg_clone (fimg-core.c:174)
==28943== by 0x401861: essai_filtrage_3x3 (t.c:118)
==28943== by 0x4024D5: main (t.c:444)
*/
return count;
}
/* ---------------------------------------------------------------- */
int fimg_mul_cste(FloatImg *fi, float value)
{
int nbre, idx;
if ( (fi->type != FIMG_TYPE_RGB) && (fi->type != FIMG_TYPE_GRAY) ) {
fprintf(stderr, "%s : type %d invalide\n",
__func__, fi->type);
return -44;
}
nbre = fi->width * fi->height;
#if DEBUG_LEVEL
fprintf(stderr, "%s, nbre of datum is %d\n", __func__, nbre);
#endif
if (fi->type == FIMG_TYPE_RGB) {
for (idx=0; idx<nbre; idx++) {
fi->R[idx] *= value;
fi->G[idx] *= value;
fi->B[idx] *= value;
}
}
if (fi->type == FIMG_TYPE_GRAY) {
for (idx=0; idx<nbre; idx++) {
fi->R[idx] *= value;
}
}
return 0;
}
/* ---------------------------------------------------------------- */
/* nouveau 17 septembre 2022 */
int fimg_div_cste(FloatImg *fi, float value)
{
int nbre, idx;
if ( (fi->type != FIMG_TYPE_RGB) && (fi->type != FIMG_TYPE_GRAY) ) {
fprintf(stderr, "%s : type %d invalide\n",
__func__, fi->type);
return -44;
}
nbre = fi->width * fi->height;
if (fi->type == FIMG_TYPE_RGB) {
for (idx=0; idx<nbre; idx++) {
fi->R[idx] /= value;
fi->G[idx] /= value;
fi->B[idx] /= value;
}
}
if (fi->type == FIMG_TYPE_GRAY) {
for (idx=0; idx<nbre; idx++) {
fi->R[idx] /= value;
}
}
return 0;
}
/* ---------------------------------------------------------------- */
/*
* oh, please explain the usecase of this function !
*/
int fimg_ajust_from_grab(FloatImg *fi, double maxima, int notused)
{
double coef;
if (notused) {
fprintf(stderr, "notused was %d, must be 0 in %s\n",
notused, __func__);
}
if (fi->type != FIMG_TYPE_RGB) {
fprintf(stderr, "%s : type %d invalide\n",
__func__, fi->type);
return -99;
}
if (fi->count < 1) {
fprintf(stderr, "%s : count %d is invalid\n", __func__, fi->count);
return -98;
}
/*
* mmmm, is this real ?
* how to accuratly check the value of 'I.fval' ?
*/
coef = 1.0 / ((double)fi->count * (double)fi->fval);
if (verbosity) {
fprintf(stderr, "image @ %p\n", fi);
fprintf(stderr, "fval %f\n", fi->fval);
fprintf(stderr, "count %d\n", fi->count);
fprintf(stderr, "maxima %f\n", maxima);
fprintf(stderr, "coef %f\n", coef);
}
fimg_mul_cste(fi, coef);
return 0;
}
/* ---------------------------------------------------------------- */
int fimg_absolute(FloatImg *fi)
{
int surface, idx;
surface = fi->width * fi->height;
for (idx=0; idx<surface; idx++) {
fi->R[idx] = fabsf(fi->R[idx]);
fi->G[idx] = fabsf(fi->G[idx]);
fi->B[idx] = fabsf(fi->B[idx]);
}
return 0;
}
/* ---------------------------------------------------------------- */
/* Warning: this function is _very_ slow */
void fimg_drand48(FloatImg *fi, float kmul)
{
int nbre, idx;
#if DEBUG_LEVEL
fprintf(stderr, ">>> %s ( %p %g )\n", __func__, fi, kmul);
#endif
if (fi->type != FIMG_TYPE_RGB) {
fprintf(stderr, "%s : type %d invalide\n",
__func__, fi->type);
return;
}
nbre = fi->width * fi->height;
fprintf(stderr, "in %s, drand48() is %f\n", __func__, drand48());
for (idx=0; idx<nbre; idx++) {
fi->R[idx] = drand48() * kmul;
fi->G[idx] = drand48() * kmul;
fi->B[idx] = drand48() * kmul;
}
}
/* ---------------------------------------------------------------- */