Skip to content

Commit b9e3074

Browse files
authored
add matrixmultiply (#4371)
* add matrixmultiply needed for nip4 compat mode * fix matrixload sniff for some matrix files (#4372) matrixload is_a could fail to detect files like this: ``` 2 2 0 0 1 1 ``` The header parser was not stopping at EOL and thought that this file had scale 0, which it would then reject. * fix invertlut in some cases (#4373) If the measurements filled the entire x range, we were not writing the final value. For example: ``` 2 2 0 0 1 1 ``` ``` $ vips invertlut linear.mat x2.v $ vips getpoint x2.v 255 0 -nan ``` With this PR you get 1, as expected.
1 parent 415fcb0 commit b9e3074

File tree

6 files changed

+205
-1
lines changed

6 files changed

+205
-1
lines changed

ChangeLog

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
- tiffload: add support for unlimited flag (requires libtiff 4.7.0+) [lovell]
88
- much more reliable operation caching
99
- colour: add support for auto-selecting the rendering intent [kleisauke]
10+
- add matrixmultiply
1011

1112
8.16.1
1213

libvips/include/vips/mosaicing.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,10 @@ VIPS_API
7272
int vips_matrixinvert(VipsImage *m, VipsImage **out, ...)
7373
G_GNUC_NULL_TERMINATED;
7474

75+
VIPS_API
76+
int vips_matrixmultiply(VipsImage *left, VipsImage *right, VipsImage **out, ...)
77+
G_GNUC_NULL_TERMINATED;
78+
7579
#ifdef __cplusplus
7680
}
7781
#endif /*__cplusplus*/

libvips/mosaicing/matrixinvert.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -436,7 +436,7 @@ vips_matrixinvert_class_init(VipsMatrixinvertClass *class)
436436
gobject_class->get_property = vips_object_get_property;
437437

438438
vobject_class->nickname = "matrixinvert";
439-
vobject_class->description = _("invert an matrix");
439+
vobject_class->description = _("invert a matrix");
440440
vobject_class->build = vips_matrixinvert_build;
441441

442442
VIPS_ARG_IMAGE(class, "in", 0,

libvips/mosaicing/matrixmultiply.c

Lines changed: 196 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,196 @@
1+
/* Multiply two matrices.
2+
*
3+
* Copyright: 1990, K. Martinez and J. Cupitt
4+
*
5+
* 23/10/10
6+
* - gtk-doc
7+
* 31/1/25
8+
* - wrapped as a class
9+
*/
10+
11+
/*
12+
13+
This file is part of VIPS.
14+
15+
VIPS is free software; you can redistribute it and/or modify
16+
it under the terms of the GNU Lesser General Public License as published by
17+
the Free Software Foundation; either version 2 of the License, or
18+
(at your option) any later version.
19+
20+
This program is distributed in the hope that it will be useful,
21+
but WITHOUT ANY WARRANTY; without even the implied warranty of
22+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
23+
GNU Lesser General Public License for more details.
24+
25+
You should have received a copy of the GNU Lesser General Public License
26+
along with this program; if not, write to the Free Software
27+
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
28+
02110-1301 USA
29+
30+
*/
31+
32+
/*
33+
34+
These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk
35+
36+
*/
37+
38+
#ifdef HAVE_CONFIG_H
39+
#include <config.h>
40+
#endif /*HAVE_CONFIG_H*/
41+
#include <glib/gi18n-lib.h>
42+
43+
#include <stdio.h>
44+
45+
#include <vips/vips.h>
46+
47+
/* Our state.
48+
*/
49+
typedef struct _VipsMatrixmultiply {
50+
VipsOperation parent_instance;
51+
52+
VipsImage *left;
53+
VipsImage *right;
54+
VipsImage *out;
55+
56+
VipsImage *mat1;
57+
VipsImage *mat2;
58+
59+
} VipsMatrixmultiply;
60+
61+
typedef VipsOperationClass VipsMatrixmultiplyClass;
62+
63+
G_DEFINE_TYPE(VipsMatrixmultiply, vips_matrixmultiply, VIPS_TYPE_OPERATION);
64+
65+
static void
66+
vips_matrixmultiply_dispose(GObject *gobject)
67+
{
68+
VipsMatrixmultiply *matrix = (VipsMatrixmultiply *) gobject;
69+
70+
VIPS_UNREF(matrix->mat1);
71+
VIPS_UNREF(matrix->mat2);
72+
73+
G_OBJECT_CLASS(vips_matrixmultiply_parent_class)->dispose(gobject);
74+
}
75+
76+
static int
77+
vips_matrixmultiply_build(VipsObject *object)
78+
{
79+
VipsObjectClass *class = VIPS_OBJECT_GET_CLASS(object);
80+
VipsMatrixmultiply *matrix = (VipsMatrixmultiply *) object;
81+
82+
if (VIPS_OBJECT_CLASS(vips_matrixmultiply_parent_class)->build(object))
83+
return -1;
84+
85+
if (vips_check_matrix(class->nickname, matrix->left, &matrix->mat1) ||
86+
vips_check_matrix(class->nickname, matrix->right, &matrix->mat2))
87+
return -1;
88+
89+
if (matrix->mat1->Xsize != matrix->mat2->Ysize) {
90+
vips_error(class->nickname, "%s", _("bad sizes"));
91+
return -1;
92+
}
93+
94+
g_object_set(matrix,
95+
"out", vips_image_new_matrix(matrix->mat2->Xsize, matrix->mat1->Ysize),
96+
NULL);
97+
98+
/* Multiply.
99+
*/
100+
double *out;
101+
double *s1;
102+
103+
s1 = VIPS_MATRIX(matrix->mat1, 0, 0);
104+
out = VIPS_MATRIX(matrix->out, 0, 0);
105+
for (int yc = 0; yc < matrix->mat1->Ysize; yc++) {
106+
double *s2 = VIPS_MATRIX(matrix->mat2, 0, 0);
107+
108+
for (int col = 0; col < matrix->mat2->Xsize; col++) {
109+
/* Get ready to sweep a row.
110+
*/
111+
double *a = s1;
112+
double *b = s2;
113+
114+
double sum;
115+
116+
sum = 0.0;
117+
for (int xc = 0; xc < matrix->mat1->Xsize; xc++) {
118+
sum += *a++ * *b;
119+
b += matrix->mat2->Xsize;
120+
}
121+
122+
*out++ = sum;
123+
s2 += 1;
124+
}
125+
126+
s1 += matrix->mat1->Xsize;
127+
}
128+
129+
return 0;
130+
}
131+
132+
static void
133+
vips_matrixmultiply_class_init(VipsMatrixmultiplyClass *class)
134+
{
135+
GObjectClass *gobject_class = G_OBJECT_CLASS(class);
136+
VipsObjectClass *vobject_class = VIPS_OBJECT_CLASS(class);
137+
138+
gobject_class->dispose = vips_matrixmultiply_dispose;
139+
gobject_class->set_property = vips_object_set_property;
140+
gobject_class->get_property = vips_object_get_property;
141+
142+
vobject_class->nickname = "matrixmultiply";
143+
vobject_class->description = _("multiply two matrices");
144+
vobject_class->build = vips_matrixmultiply_build;
145+
146+
VIPS_ARG_IMAGE(class, "left", 1,
147+
_("Left"),
148+
_("First matrix to multiply"),
149+
VIPS_ARGUMENT_REQUIRED_INPUT,
150+
G_STRUCT_OFFSET(VipsMatrixmultiply, left));
151+
152+
VIPS_ARG_IMAGE(class, "right", 2,
153+
_("Right"),
154+
_("Second matrix to multiply"),
155+
VIPS_ARGUMENT_REQUIRED_INPUT,
156+
G_STRUCT_OFFSET(VipsMatrixmultiply, right));
157+
158+
VIPS_ARG_IMAGE(class, "out", 3,
159+
_("Output"),
160+
_("Output matrix"),
161+
VIPS_ARGUMENT_REQUIRED_OUTPUT,
162+
G_STRUCT_OFFSET(VipsMatrixmultiply, out));
163+
}
164+
165+
static void
166+
vips_matrixmultiply_init(VipsMatrixmultiply *matrix)
167+
{
168+
}
169+
170+
/**
171+
* vips_matrixmultiply: (method)
172+
* @left: input matrix
173+
* @right: input matrix
174+
* @out: (out): output matrix
175+
* @...: %NULL-terminated list of optional named arguments
176+
*
177+
* Multiplies two matrix images.
178+
*
179+
* The scale and offset members of @left and @right are ignored.
180+
*
181+
* See also: vips_matrixinvert().
182+
*
183+
* Returns: 0 on success, -1 on error
184+
*/
185+
int
186+
vips_matrixmultiply(VipsImage *left, VipsImage *right, VipsImage **out, ...)
187+
{
188+
va_list ap;
189+
int result;
190+
191+
va_start(ap, out);
192+
result = vips_call_split("matrixmultiply", ap, left, right, out);
193+
va_end(ap);
194+
195+
return result;
196+
}

libvips/mosaicing/meson.build

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ mosaicing_sources = files(
66
'mosaic1.c',
77
'chkpair.c',
88
'matrixinvert.c',
9+
'matrixmultiply.c',
910
'global_balance.c',
1011
'lrmerge.c',
1112
'tbmerge.c',

libvips/mosaicing/mosaicing.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,11 +97,13 @@ vips_mosaicing_operation_init(void)
9797
extern GType vips_match_get_type(void);
9898
extern GType vips_globalbalance_get_type(void);
9999
extern GType vips_matrixinvert_get_type(void);
100+
extern GType vips_matrixmultiply_get_type(void);
100101

101102
vips_merge_get_type();
102103
vips_mosaic_get_type();
103104
vips_mosaic1_get_type();
104105
vips_matrixinvert_get_type();
106+
vips_matrixmultiply_get_type();
105107
vips_match_get_type();
106108
vips_globalbalance_get_type();
107109
}

0 commit comments

Comments
 (0)