/***************************************************************************** * * * Programm: paul * * (P)rogramm zur (A)uswertung und (U)mformung von * * (L)aserbildern * * Modul: difpic.c * * Funktions to calculate difference images * * Author: Andreas Tille * * Date: 27.02.1998 * * Copyright: Andreas Tille, 1999; GNU Public License * * * *****************************************************************************/ #include <math.h> #include <stdio.h> #include <string.h> #include "paul.h" #include "names.h" #define MINCOL 0xFF #define MAXCOL 0x00 static int strxcmp(const char *s1, const char *s2) /* obtain the matching first characters of two strings * --- Parameter: --- * const char *s1, *s2: strings to compare * --- Return: --- * int strxcmp() : number of matching characters in the beginning of the * two strings */ { register char *p1 = (char *)s1 - 1, *p2 = (char *)s2 - 1; while ( *(++p1) && *(++p2) ) if ( *p1 != *p2 ) break; return p1 - s1; } static int strbxcmp(const char *s1, const char *s2) /* obtain the matching last characters of two strings * --- Parameter: --- * const char *s1, *s2: strings to compare * --- Return: --- * int strbxcmp() : number of matching characters in the end of the * two strings */ { register char *p1 = (char *)s1 + strlen(s1), *p2 = (char *)s2 + strlen(s2), *ss; ss = p1 - 1; while ( *(--p1) && *(--p2) ) if ( *p1 != *p2 ) break; return ss - p1; } static char *DiffBildName(char *bild1, char *bild2) /* obtain the name of difference image from to source image names * The comon parts of both sources at the beginning and the end (except extension) * will be used. The different part in the middle will be stored as * _[img1]-[img2]_ * --- Parameter: --- * char *bild1 : name of first image * char *bild2 : name of second image * --- Return: --- * char *DiffBildName(): name of difference image (memory will be allocated * ... and some space for extension will be saved) */ { char *buf, *pb; register int n, m, i; buf = g_malloc(strlen(bild1) + strlen(bild2) + 20); strncpy(buf, bild1, n = strxcmp(bild1,bild2)); *(pb = buf + n) = '_'; ++pb; if ( n == strlen(bild1) ) { *(pb++) = '-'; if ( n != strlen(bild2) ) strcpy(pb, bild2 + n); *(pb += strlen(bild2+n)) = '_'; ++pb; } else if ( n == strlen(bild2) ) { if ( n != strlen(bild1) ) strcpy(pb, bild1 + n); *(pb += strlen(bild1+n)) = '-'; *(++pb) = '_'; ++pb; } else { m = strbxcmp(bild1,bild2); if ( (i = strlen(bild1) - n - m) > 0 ) strncpy(pb, bild1 + n, i); else i = 1; /* This makes not much sense but avoids crashs for some unusual cases */ *(pb += i) = '-'; ++pb; if ( (i = strlen(bild2) - n - m) > 0 ) strncpy(pb, bild2 + n, i); else i = 1; /* This makes not much sense but avoids crashs for some unusual cases */ *(pb += i) = '_'; ++pb; if ( m ) strncpy(pb, bild1 + strlen(bild1) - m, m); pb += m; } *pb = 0; pb = g_strdup(buf); FREE(buf); return pb; } static int DifferenceImage(PICTURE *bild1, PICTURE *bild2, OPTIONS *opt) /* difference of pixels image1 - image2 * --- Parameter: --- * PICTURE *bild1 : image which is subject to change * PICTURE *bild2 : image to subtract from first image * OPTIONS *opt : used options: * eps : noise threshold, lower values will be set to 0 * offset: shift of brightness * scale : contrast factor * --- Return: --- * PICTURE *bild1 : bild1 now contains difference image * int DifferenceImage(): RET_OK, RET_ERR; */ { unsigned char eps = opt->eps, offset = opt->offset; double scale = opt->scale; register int d; register unsigned char *a, *b, *u, *v, *fip; char *desc; g_return_val_if_fail( IS_PICTURE(bild1), RET_ERR ); g_return_val_if_fail( IS_PICTURE(bild2), RET_ERR ); if ( bild1->W != bild2->W || bild1->H != bild2->H ) { g_warning(_("%s and %s have different size (%ix%i resp. %ix%i).\nTry using \"%s\" to get equal sized images."), bild1->file, bild2->file, bild1->W, bild1->H, bild2->W, bild2->H, Mo_ve); return RET_ERR; } if ( !IsMonochrom(bild1) ) MakeSingleGreen(bild1, opt->greps); if ( !IsMonochrom(bild2) ) MakeSingleGreen(bild2, opt->greps); desc = g_strdup_printf("%s - %s", bild1->file, bild2->file); ImgChunksUpdate(bild1, TypDifferenzBild, desc, NULL, DIFFERENZ); FREE(desc); desc = DiffBildName(bild1->file, bild2->file); FREE(bild1->file); bild1->file = desc; bild1->spp = 3; a = (bild1->DATA) + 1; b = (bild2->DATA) + 1; for ( fip = a + 3 * (bild1->size); a < fip; a += 3, b += 3) { if ( (d = (int)*a - (int)*b) < 0 ) { u = a - 1; /* bild1 < bild2 => store Difference in red channel */ v = a + 1; /* => set blue channel 0 */ } else { u = a + 1; v = a - 1; } if ( (d = abs(d)) < eps ) { /* suppress noise */ *(a-1) = *a = *(a+1) = 0xFF; /* zero differnce set white in favour of black because * * of higher contrast */ continue; } d = d * scale + offset; /* enhance contrast and brightness */ *u = (unsigned char)(d < 0x100 ? d : 0xFF); *a = *v = 0; } return RET_OK; } int DifferenceQueue(PAUL *p) /* Differences of a list of images * --- Parameter: --- * PAUL *p : list of images, options * : used options: * eps : noise border * offset : increase brightness of difference image * scale : increase contrast of difference image * --- return: --- * p->piclist : new list of images containing differences * int DifferenceQueue(): RET_ERR or RET_OK */ { GList *pl; g_return_val_if_fail ( IS_PAUL(p), RET_ERR ); if ( !(p->piclist) ) return RET_ERR; g_return_val_if_fail ( CheckPicList(p->piclist), RET_ERR ) ; if ( NBILDER(p->piclist) < 2 ) return RET_OK; for ( pl = p->piclist; pl->next; pl = pl->next ) if ( DifferenceImage(BILD(pl), BILD(pl->next), p->opt) ) return RET_ERR; FreePiclist(g_list_last(p->piclist)); g_list_remove_link(p->piclist, g_list_last(p->piclist)); p->opt->f &= ~DIFFERENZ; return RET_OK; } int MakeDifference(PAUL *p) /* Difference of operating image to all other images * --- Parameter: --- * PAUL *p : list of images, options * : used options: * eps : noise border * offset : increase brightness of difference image * scale : increase contrast of difference image * --- return: --- * p->piclist : new list of images containing differences * int MakeDifference() : RET_ERR or RET_OK */ { GList *pl; g_return_val_if_fail ( IS_PAUL(p), RET_ERR ) ; if ( !(p->piclist) ) return RET_ERR; g_return_val_if_fail ( CheckPicList(p->piclist), RET_ERR ) ; if ( !CheckOperating(p) ) return RET_ERR; for ( pl = p->piclist; pl; pl = pl->next ) if ( DifferenceImage(BILD(pl), p->op, p->opt) ) return RET_ERR; p->opt->f &= ~DIFFERENZ; return RET_OK; }