Statistics
| Revision:

svn-gvsig-desktop / branches / org.gvsig.desktop-2018a / org.gvsig.desktop.library / org.gvsig.raster / org.gvsig.raster.lib / org.gvsig.raster.lib.buffer.impl / src / main / java / org / gvsig / raster / lib / buffer / impl / operations / edgedetection / firstderivative / FirstDerivativeOperation.java @ 43835

History | View | Annotate | Download (23.9 KB)

1
/* gvSIG. Desktop Geographic Information System.
2
 *
3
 * Copyright ? 2007-2017 gvSIG Association
4
 *
5
 * This program is free software; you can redistribute it and/or
6
 * modify it under the terms of the GNU General Public License
7
 * as published by the Free Software Foundation; either version 2
8
 * of the License, or (at your option) any later version.
9
 *
10
 * This program is distributed in the hope that it will be useful,
11
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13
 * GNU General Public License for more details.
14
 *
15
 * You should have received a copy of the GNU General Public License
16
 * along with this program; if not, write to the Free Software
17
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
18
 * MA  02110-1301, USA.
19
 *
20
 * For any additional information, do not hesitate to contact us
21
 * at info AT gvsig.com, or visit our website www.gvsig.com.
22
 */
23
package org.gvsig.raster.lib.buffer.impl.operations.edgedetection.firstderivative;
24

    
25
import java.util.ArrayList;
26
import java.util.Iterator;
27
import java.util.List;
28

    
29
import org.gvsig.fmap.geom.exception.CreateEnvelopeException;
30
import org.gvsig.raster.lib.buffer.api.Band;
31
import org.gvsig.raster.lib.buffer.api.BufferLocator;
32
import org.gvsig.raster.lib.buffer.api.BufferManager;
33
import org.gvsig.raster.lib.buffer.api.Kernel;
34
import org.gvsig.raster.lib.buffer.api.NoData;
35
import org.gvsig.raster.lib.buffer.api.exceptions.BandException;
36
import org.gvsig.raster.lib.buffer.api.exceptions.BufferException;
37
import org.gvsig.raster.lib.buffer.api.exceptions.BufferOperationException;
38
import org.gvsig.raster.lib.buffer.api.operations.OperationFactory;
39
import org.gvsig.raster.lib.buffer.spi.exceptions.ProcessingOperationException;
40
import org.gvsig.raster.lib.buffer.spi.operations.AbstractSpecifiedBandsOperation;
41
import org.gvsig.tools.locator.LocatorException;
42

    
43

    
44
/**
45
 * @author fdiaz
46
 *
47
 */
48
public class FirstDerivativeOperation extends AbstractSpecifiedBandsOperation{
49

    
50
    static final public String SOBEL_OPERATOR_STRING= "SOBEL";
51
    static final public String ROBERTS_OPERATOR_STRING= "ROBERTS";
52
    static final public String PREWITT_OPERATOR_STRING= "PREWITT";
53
    static final public String FREICHEN_OPERATOR_STRING= "FREICHEN";
54

    
55
    static public String OPERATOR_PARAM = "operator";
56
    static public String UMBRAL_PARAM = "umbral";
57
    static public String COMPARE_PARAM = "compare";
58

    
59
    private String operator;
60
    private int umbral;
61
    private boolean compare;
62
    private RowProcessor[] rowProcessors;
63
    private Kernel operatorH;
64
    private Kernel operatorV;
65

    
66
    static final private int SIDE_WINDOW = 3;
67
    static final private int HALF_SIDE_WINDOW = 1;
68

    
69

    
70
    // Kernels:------------------------------------------
71
    static final double     sobelH[][]      = {{-1,0,1},{-2,0,2},{-1,0,1}};
72
    static final double     sobelV[][]      = {{-1,-2,-1},{0,0,0},{1,2,1}};
73

    
74
    static final double     robertsH[][]    = {{0,0,-1},{0,1,0},{0,0,0}};
75
    static final double     robertsV[][]    = {{-1,0,0},{0,1,0},{0,0,0}};
76

    
77
    static final double     prewittH[][]    = {{1,0,-1},{1,0,-1},{1,0,-1}};
78
    static final double     prewittV[][]    = {{-1,-1,-1},{0,0,0},{1,1,1}};
79
    static final double     sqr2            = Math.sqrt(2);
80
//    static final double     freiChenH[][]   = {{-1,-sqr2,-1},{0,0,0},{1,sqr2,1}};
81
//    static final double     freiChenV[][]   = {{-1,0,1},{-sqr2,0,sqr2},{-1,0,1}};
82

    
83
    static final double     freiChenH[][]   = {{-1,-1.4D,-1},{0,0,0},{1,1.4D,1}};
84
    static final double     freiChenV[][]   = {{-1,0,1},{-1.4D,0,1.4D},{-1,0,1}};
85

    
86

    
87
    /**
88
     * @param factory
89
     *
90
     */
91
    public FirstDerivativeOperation(OperationFactory factory) {
92
        this.factory = factory;
93
    }
94

    
95
    @Override
96
    public void preProcess() throws BufferOperationException {
97
        super.preProcess();
98
        BufferManager manager = BufferLocator.getBufferManager();
99

    
100
        if(this.parameters.getDynClass().getDynField(OPERATOR_PARAM)!=null) {
101
            operator = (String)this.parameters.getDynValue(OPERATOR_PARAM);
102
        } else {
103
            operator = SOBEL_OPERATOR_STRING;
104
        };
105

    
106
        switch (operator) {
107
        case SOBEL_OPERATOR_STRING:
108
            operatorH = manager.createKernel(sobelH);
109
            operatorV = manager.createKernel(sobelV);
110
            break;
111
        case ROBERTS_OPERATOR_STRING:
112
            operatorH = manager.createKernel(robertsH);
113
            operatorV = manager.createKernel(robertsV);
114
            break;
115
        case PREWITT_OPERATOR_STRING:
116
            operatorH = manager.createKernel(prewittH);
117
            operatorV = manager.createKernel(prewittV);
118
            break;
119
        case FREICHEN_OPERATOR_STRING:
120
            operatorH = manager.createKernel(freiChenH);
121
            operatorV = manager.createKernel(freiChenV);
122
            break;
123
        }
124

    
125
        if(this.parameters.getDynClass().getDynField(COMPARE_PARAM)!=null) {
126
            compare = (Boolean)this.parameters.getDynValue(COMPARE_PARAM);
127
        } else {
128
            compare = false;
129
        };
130
        if(this.parameters.getDynClass().getDynField(UMBRAL_PARAM)!=null) {
131
            umbral = (Integer)this.parameters.getDynValue(UMBRAL_PARAM);
132
        } else {
133
            umbral = 0;
134
        };
135

    
136
        int bands = this.buffer.getBandCount();
137
        NoData[] noData = this.buffer.getBandNoData();
138
        if (copyUnprocessedBands) {
139
            try {
140
                this.outputBuffer =
141
                    manager.createBuffer(this.buffer.getRows(), this.buffer.getColumns(), this.buffer.getBandTypes(),
142
                        this.buffer.getBandNoData(), this.buffer.getProjection(), this.buffer.getEnvelope());
143
            } catch (LocatorException | BufferException | CreateEnvelopeException e) {
144
                throw new ProcessingOperationException(e);
145
            }
146
        } else {
147
            List<NoData> noDatas = new ArrayList<NoData>();
148
            List<Integer> types = new ArrayList<Integer>();
149
            for (int band = 0; band < bands; band++) {
150
                if (isProcessableBand(band)) {
151
                    if(this.buffer.getBandNoData()[band].isDefined()){
152
                        noDatas.add(manager.createNoData(0, 0));
153
                    } else {
154
                        noDatas.add(null);
155
                    }
156
                    types.add(BufferManager.TYPE_BYTE);
157
                }
158
            }
159
            int[] typesInt = new int[types.size()];
160
            for (Iterator<Integer> iterator = types.iterator(); iterator.hasNext();) {
161
                int i = 0;
162
                Integer type = (Integer) iterator.next();
163
                typesInt[i] = type.intValue();
164
            }
165
            try {
166
                this.outputBuffer =
167
                    manager.createBuffer(this.buffer.getRows(), this.buffer.getColumns(), typesInt,
168
                        noDatas.toArray(new NoData[0]), this.buffer.getProjection(), this.buffer.getEnvelope());
169
            } catch (LocatorException | BufferException | CreateEnvelopeException e) {
170
                throw new ProcessingOperationException(e);
171
            }
172
        }
173

    
174
        rowProcessors = new RowProcessor[bands];
175
        for (int band = 0; band < noData.length; band++) {
176
            if (isProcessableBand(band)) {
177
                int bandType = this.buffer.getBand(band).getDataType();
178
                switch (bandType) {
179
                case BufferManager.TYPE_BYTE:
180
                    rowProcessors[band] = new ByteRowProcessor(band);
181
                    break;
182
                case BufferManager.TYPE_USHORT:
183
                    rowProcessors[band] = new UShortRowProcessor(band);
184
                    break;
185
                case BufferManager.TYPE_SHORT:
186
                    rowProcessors[band] = new ShortRowProcessor(band);
187
                    break;
188
                case BufferManager.TYPE_INT:
189
                    rowProcessors[band] = new IntRowProcessor(band);
190
                    break;
191
                case BufferManager.TYPE_FLOAT:
192
                    rowProcessors[band] = new FloatRowProcessor(band);
193
                    break;
194
                case BufferManager.TYPE_DOUBLE:
195
                    rowProcessors[band] = new DoubleRowProcessor(band);
196
                    break;
197
                default:
198
                    throw new IllegalArgumentException("Unknow type of band '" + band + "'");
199
                }
200
            }
201
        }
202
        }
203

    
204
    @Override
205
    public void process() throws ProcessingOperationException {
206
        super.process();
207
        for (int band=0; band<this.buffer.getBandCount(); band++){
208
            if (bandsToProcess.contains(band)) {
209
                Band bufferBand = this.buffer.getBand(band);
210
                Band outputBufferBand = this.outputBuffer.getBand(band);
211

    
212
                for (int row = 0; row < this.buffer.getRows(); row++) {
213
                    Object rowBuffer = bufferBand.createRowBuffer();
214
                    bufferBand.fetchRow(row, rowBuffer);
215
                    List<Object> bundle = new ArrayList<Object>();
216
                    //FIXME: Solo se procesan aquellas filas en las que se pueden crear kernels, el resto ?qu? hacer? (ver abajo)
217
                    if ((row - HALF_SIDE_WINDOW >= 0) && (row + HALF_SIDE_WINDOW < this.buffer.getRows())) {
218
                        for (int r = Math.max(row - HALF_SIDE_WINDOW, 0); r <= Math.min(row + HALF_SIDE_WINDOW,
219
                            this.buffer.getRows()-1); r++) {
220
                            Object bundleRow = bufferBand.createRowBuffer();
221
                            bufferBand.fetchRow(r, bundleRow);
222
                            bundle.add(bundleRow);
223
                        }
224

    
225
                        Object outputRowBuffer = outputBufferBand.createRowBuffer();
226
                        // outputBufferBand.fetchRow(row, outputRowBuffer);
227

    
228
                        rowProcessors[band].processRow(rowBuffer, bundle, outputRowBuffer);
229

    
230
                        outputBufferBand.putRow(row, outputRowBuffer);
231
                    } else {
232
                        // FIXME: Si son de tipo BYTE, las copio, si no, no hacemos nada
233
                        if(this.buffer.getBandTypes()[band]==BufferManager.TYPE_BYTE){
234
                            outputBufferBand.putRow(row, rowBuffer);
235
                        }
236
                    }
237
                }
238
            } else {
239
                if(copyUnprocessedBands){
240
                    try {
241
                        this.outputBuffer.getBand(band).copyFrom(this.buffer.getBand(band));
242
                    } catch (BandException e) {
243
                        throw new ProcessingOperationException(e);
244
                    }
245
                }
246
            }
247
        }
248
    }
249

    
250
    @Override
251
    public void postProcess()  throws BufferOperationException {
252
        super.postProcess();
253
    }
254

    
255
    interface RowProcessor {
256
        void processRow(Object inputRow, List<Object> bundleRow, Object outputRow);
257
        Number processValue(Kernel kernel);
258
    };
259

    
260
    private abstract class AbstractRowProcessor implements RowProcessor {
261
        int band;
262
        NoData noData;
263

    
264
        public AbstractRowProcessor(int band) {
265
            this.band = band;
266
            noData = buffer.getBand(band).getNoData();
267
        }
268

    
269
        @Override
270
        public Number processValue(Kernel kernel) {
271

    
272
            int convoResult[] = new int[4];
273
            int out;
274

    
275
            convoResult[0] = (int) operatorH.convolution(kernel);
276
            convoResult[1] = (int) operatorV.convolution(kernel);
277

    
278
            if (compare) {
279
                if (convoResult[0] > convoResult[1])
280
                    out = convoResult[0];
281
                else
282
                    out = convoResult[1];
283
            } else {
284
                out = (int) Math.sqrt(Math.pow(convoResult[0], 2) + Math.pow(convoResult[1], 2));
285
            }
286

    
287
            if (umbral > 0) {
288
                if (out >= (255 - umbral))
289
                    out = 255;
290
                else
291
                    out = 0;
292
            } else {
293
                if (out < 0)
294
                    out = 0;
295
                else if (out > 255)
296
                    out = 255;
297
            }
298

    
299
          return (byte)(out);
300
        }
301
    }
302

    
303
    private class ByteRowProcessor extends AbstractRowProcessor {
304

    
305

    
306
        public ByteRowProcessor(int band) {
307
            super(band);
308
        }
309

    
310
        @Override
311
        public void processRow(Object inputRow, List<Object> bundleRow, Object outputRow) {
312
            byte[] inputByteRow = (byte[])inputRow;
313
            byte[] outputByteRow = (byte[])outputRow;
314
            for (int i = 0; i < inputByteRow.length; i++) {
315
                // FIXME: Solo se procesan aquellas columnas en las que se pueden crear kernels, el resto ?se copian?
316
                if ((i - HALF_SIDE_WINDOW >= 0) && (i + HALF_SIDE_WINDOW < inputByteRow.length)) {
317
                    double[][] k = new double[SIDE_WINDOW][SIDE_WINDOW];
318
                    int r=0;
319
                    for (Iterator<Object> iterator = bundleRow.iterator(); iterator.hasNext();) {
320
                        int c=0;
321
                        byte[] row = (byte[]) iterator.next();
322
                        for (int column = Math.max(i - HALF_SIDE_WINDOW, 0); column <= Math.min(i + HALF_SIDE_WINDOW,
323
                            inputByteRow.length-1); column++) {
324
                            byte value = ((Byte) row[column]).byteValue();
325
                            if (noData.isDefined() && noData.getValue().equals(value)) {
326
                                //FIXME: Si es noData, deber?a no influir en el resultado
327
                                // ?Que valor poner en el kernel?
328
                                k[r][c] = 0;
329
                            } else {
330
                                k[r][c] = (double)(0xFF & value);
331
                            }
332
                            c++;
333
                        }
334
                        r++;
335
                    }
336
                    Kernel kernel = BufferLocator.getBufferManager().createKernel(k);
337
                    if(noData.isDefined() && noData.getValue().equals(inputByteRow[i])){
338
                        outputByteRow[i] = inputByteRow[i];
339
                    } else {
340
                        outputByteRow[i] = processValue(kernel).byteValue();
341
                    }
342
                } else {
343
                    outputByteRow[i] = inputByteRow[i];
344
                }
345
            }
346
        }
347
    }
348

    
349
    private class ShortRowProcessor extends AbstractRowProcessor {
350

    
351
        public ShortRowProcessor(int band) {
352
            super(band);
353
        }
354

    
355
        @Override
356
        public void processRow(Object inputRow, List<Object> bundleRow, Object outputRow) {
357
            Number[] inputShortRow = (Number[])inputRow;
358
            byte[] outputByteRow = (byte[])outputRow;
359
            for (int i = 0; i < inputShortRow.length; i++) {
360
                //Solo se procesan aquellas columnas en las que se pueden crear kernels, el resto se copian
361
                if ((i - HALF_SIDE_WINDOW >= 0) && (i + HALF_SIDE_WINDOW < inputShortRow.length)) {
362
                    double[][] k = new double[SIDE_WINDOW][SIDE_WINDOW];
363
                    int r=0;
364
                    int c=0;
365
                    for (Iterator<Object> iterator = bundleRow.iterator(); iterator.hasNext();) {
366
                        short[] row = (short[]) iterator.next();
367
                        for (int column = Math.max(i - HALF_SIDE_WINDOW, 0); column <= Math.min(i + HALF_SIDE_WINDOW,
368
                            inputShortRow.length-1); column++) {
369
                            double value = ((Short) row[c]).shortValue();
370
                            if (noData.isDefined() && noData.getValue().equals(value)) {
371
                                //FIXME: Si es noData, deber?a no influir en el resultado
372
                                // ?Que valor poner en el kernel?
373
                                k[r][c] = 0;
374
                            } else {
375
                                k[r][c] = value;
376
                            }
377
                        }
378
                    }
379
                    Kernel kernel = BufferLocator.getBufferManager().createKernel(k);
380
                    outputByteRow[i] = processValue(kernel).byteValue();
381
                } else {
382
                    outputByteRow[i] = ((Short)inputShortRow[i]).byteValue();
383
                }
384
            }
385
        }
386

    
387
    }
388

    
389
    private class UShortRowProcessor extends AbstractRowProcessor {
390

    
391
        public UShortRowProcessor(int band) {
392
            super(band);
393
        }
394

    
395
        @Override
396
        public void processRow(Object inputRow, List<Object> bundleRow, Object outputRow) {
397

    
398
            Number[] inputShortRow = (Number[]) inputRow;
399
            byte[] outputByteRow = (byte[]) outputRow;
400
            for (int i = 0; i < inputShortRow.length; i++) {
401
                // Solo se procesan aquellas columnas en las que se pueden crear
402
                // kernels, el resto se copian
403
                if ((i - HALF_SIDE_WINDOW >= 0) && (i + HALF_SIDE_WINDOW < inputShortRow.length)) {
404
                    double[][] k = new double[SIDE_WINDOW][SIDE_WINDOW];
405
                    int r = 0;
406
                    int c = 0;
407
                    for (Iterator<Object> iterator = bundleRow.iterator(); iterator.hasNext();) {
408
                        short[] row = (short[]) iterator.next();
409
                        for (int column = Math.max(i - HALF_SIDE_WINDOW, 0); column <= Math.min(i + HALF_SIDE_WINDOW,
410
                            inputShortRow.length-1); column++) {
411
                            double value = 0xFFFF & ((Short) row[c]).shortValue();
412
                            if (noData.isDefined() && noData.getValue().equals(value)) {
413
                                // FIXME: Si es noData, deber?a no influir en el
414
                                // resultado
415
                                // ?Que valor poner en el kernel?
416
                                k[r][c] = 0;
417
                            } else {
418
                                k[r][c] = value;
419
                            }
420
                        }
421
                    }
422
                    Kernel kernel = BufferLocator.getBufferManager().createKernel(k);
423
                    outputByteRow[i] = processValue(kernel).byteValue();
424
                } else {
425
                    outputByteRow[i] = ((Short) inputShortRow[i]).byteValue();
426
                }
427
            }
428
        }
429
    }
430

    
431
    private class IntRowProcessor extends AbstractRowProcessor {
432

    
433

    
434
        public IntRowProcessor(int band) {
435
            super(band);
436
        }
437

    
438
        @Override
439
        public void processRow(Object inputRow, List<Object> bundleRow, Object outputRow) {
440
            Number[] inputIntRow = (Number[])inputRow;
441
            byte[] outputByteRow = (byte[]) outputRow;
442
            for (int i = 0; i < inputIntRow.length; i++) {
443
                // Solo se procesan aquellas columnas en las que se pueden crear
444
                // kernels, el resto se copian
445
                if ((i - HALF_SIDE_WINDOW >= 0) && (i + HALF_SIDE_WINDOW < inputIntRow.length)) {
446
                    double[][] k = new double[SIDE_WINDOW][SIDE_WINDOW];
447
                    int r = 0;
448
                    int c = 0;
449
                    for (Iterator<Object> iterator = bundleRow.iterator(); iterator.hasNext();) {
450
                        int[] row = (int[]) iterator.next();
451
                        for (int column = Math.max(i - HALF_SIDE_WINDOW, 0); column <= Math.min(i + HALF_SIDE_WINDOW,
452
                            inputIntRow.length-1); column++) {
453
                            double value = ((Integer) row[c]).intValue();
454
                            if (noData.isDefined() && noData.getValue().equals(value)) {
455
                                // FIXME: Si es noData, deber?a no influir en el
456
                                // resultado
457
                                // ?Que valor poner en el kernel?
458
                                k[r][c] = 0;
459
                            } else {
460
                                k[r][c] = value;
461
                            }
462
                        }
463
                    }
464
                    Kernel kernel = BufferLocator.getBufferManager().createKernel(k);
465
                    outputByteRow[i] = processValue(kernel).byteValue();
466
                } else {
467
                    outputByteRow[i] = ((Integer) inputIntRow[i]).byteValue();
468
                }
469
            }
470
        }
471
    }
472
    private class FloatRowProcessor extends AbstractRowProcessor {
473

    
474

    
475
        public FloatRowProcessor(int band) {
476
            super(band);
477
        }
478

    
479
        @Override
480
        public void processRow(Object inputRow, List<Object> bundleRow, Object outputRow) {
481
            Number[] inputFloatRow = (Number[])inputRow;
482
            byte[] outputByteRow = (byte[]) outputRow;
483
            for (int i = 0; i < inputFloatRow.length; i++) {
484
                // Solo se procesan aquellas columnas en las que se pueden crear
485
                // kernels, el resto se copian
486
                if ((i - HALF_SIDE_WINDOW >= 0) && (i + HALF_SIDE_WINDOW < inputFloatRow.length)) {
487
                    double[][] k = new double[SIDE_WINDOW][SIDE_WINDOW];
488
                    int r = 0;
489
                    int c = 0;
490
                    for (Iterator<Object> iterator = bundleRow.iterator(); iterator.hasNext();) {
491
                        float[] row = (float[]) iterator.next();
492
                        for (int column = Math.max(i - HALF_SIDE_WINDOW, 0); column <= Math.min(i + HALF_SIDE_WINDOW,
493
                            inputFloatRow.length-1); column++) {
494
                            Float value = ((Float) row[c]).floatValue();
495
                            if (noData.isDefined() && noData.getValue().equals(value)) {
496
                                // FIXME: Si es noData, deber?a no influir en el
497
                                // resultado
498
                                // ?Que valor poner en el kernel?
499
                                k[r][c] = 0;
500
                            } else {
501
                                k[r][c] = value;
502
                            }
503
                        }
504
                    }
505
                    Kernel kernel = BufferLocator.getBufferManager().createKernel(k);
506
                    outputByteRow[i] = processValue(kernel).byteValue();
507
                } else {
508
                    outputByteRow[i] = ((Float) inputFloatRow[i]).byteValue();
509
                }
510
            }
511
        }
512
    }
513
    private class DoubleRowProcessor extends AbstractRowProcessor {
514

    
515

    
516
        public DoubleRowProcessor(int band) {
517
            super(band);
518
        }
519

    
520
        @Override
521
        public void processRow(Object inputRow, List<Object> bundleRow, Object outputRow) {
522
            Number[] inputDoubleRow = (Number[])inputRow;
523
            byte[] outputByteRow = (byte[]) outputRow;
524
            for (int i = 0; i < inputDoubleRow.length; i++) {
525
                // Solo se procesan aquellas columnas en las que se pueden crear
526
                // kernels, el resto se copian
527
                if ((i - HALF_SIDE_WINDOW >= 0) && (i + HALF_SIDE_WINDOW < inputDoubleRow.length)) {
528
                    double[][] k = new double[SIDE_WINDOW][SIDE_WINDOW];
529
                    int r = 0;
530
                    int c = 0;
531
                    for (Iterator<Object> iterator = bundleRow.iterator(); iterator.hasNext();) {
532
                        double[] row = (double[]) iterator.next();
533
                        for (int column = Math.max(i - HALF_SIDE_WINDOW, 0); column <= Math.min(i + HALF_SIDE_WINDOW,
534
                            inputDoubleRow.length-1); column++) {
535
                            Double value = ((Double) row[c]).doubleValue();
536
                            if (noData.isDefined() && noData.getValue().equals(value)) {
537
                                // FIXME: Si es noData, deber?a no influir en el resultado
538
                                // ?Que valor poner en el kernel?
539
                                k[r][c] = 0;
540
                            } else {
541
                                k[r][c] = value;
542
                            }
543
                        }
544
                    }
545
                    Kernel kernel = BufferLocator.getBufferManager().createKernel(k);
546
                    outputByteRow[i] = processValue(kernel).byteValue();
547
                } else {
548
                    outputByteRow[i] = ((Double) inputDoubleRow[i]).byteValue();
549
                }
550
            }
551
        }
552
    }
553
}