Vous avez reçu un message "Your GitLab account has been locked ..." ? Pas d'inquiétude : lisez cet article https://docs.gricad-pages.univ-grenoble-alpes.fr/help/unlock/

ImageLutWidget.cpp 20.5 KB
Newer Older
1
/*****************************************************************************
2
3
4
 * $CAMITK_LICENCE_BEGIN$
 *
 * CamiTK - Computer Assisted Medical Intervention ToolKit
5
 * (c) 2001-2018 Univ. Grenoble Alpes, CNRS, TIMC-IMAG UMR 5525 (GMCAO)
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
 *
 * Visit http://camitk.imag.fr for more information
 *
 * This file is part of CamiTK.
 *
 * CamiTK is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License version 3
 * only, as published by the Free Software Foundation.
 *
 * CamiTK is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Lesser General Public License version 3 for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * version 3 along with CamiTK.  If not, see <http://www.gnu.org/licenses/>.
 *
 * $CAMITK_LICENCE_END$
 ****************************************************************************/
25
26
27
28
29
30
31

// -- Core image component stuff
#include "ImageLutWidget.h"
#include "ImageComponent.h"


// -- Core stuff
32
#include "Log.h"
33
34
35
36
37
38
39

// -- QT stuff
#include <QGraphicsTextItem>
#include <QColorDialog>
#include <QPushButton>

// -- stl stuff
40
#include <cfloat>
41
42
43
44

// -- VTK stuff
#include <vtkUnsignedCharArray.h>

45
using namespace camitk;
46

47
// ---------------------- Constructor ----------------------------
48
ImageLutWidget::ImageLutWidget(QWidget* parent) : QWidget(parent) {
49

Emmanuel Promayon's avatar
Emmanuel Promayon committed
50
    myComponent = nullptr;
saubatn's avatar
saubatn committed
51
52
53

    lutMin = 0;
    lutMax = 255;
54
    nbHistoBins = 256;
55
    greyLevels = nullptr;
56
57

    // Qt model designed by QtDesigner (with qt4, nor more inheritance from the ui)
58
    ui.setupUi(this);
59

60
61
    initSlider(ui.sliderLutLevel, lutMin, lutMax, (lutMax - lutMin) / 2.0);
    initSlider(ui.sliderLutWindow, 0, (lutMax - lutMin), (lutMax - lutMin - 0.0) / 2.0);
62

63
64
65
66
    connect(ui.sliderLutLevel,    SIGNAL(valueChanged(int)), this, SLOT(sliderLUTLevelChanged(int)));
    connect(ui.sliderLutWindow,   SIGNAL(valueChanged(int)), this, SLOT(sliderLUTWindowChanged(int)));
    connect(ui.lineEditLutLevel,  SIGNAL(returnPressed()), this, SLOT(lineEditLUTLevelChanged()));
    connect(ui.lineEditLutWindow, SIGNAL(returnPressed()), this, SLOT(lineEditLUTWindowChanged()));
67

68
69
    connect(ui.maxTransparency, SIGNAL(stateChanged(int)), this, SLOT(applyLUT()));
    connect(ui.minTransparency, SIGNAL(stateChanged(int)), this, SLOT(applyLUT()));
70

71
72
    connect(ui.inversion, SIGNAL(clicked()), this, SLOT(invertButtonClicked()));
    connect(ui.resetLut,  SIGNAL(clicked()), this, SLOT(resetLUT()));
73

74
75
    connect(ui.minColor, SIGNAL(clicked()), this, SLOT(setMinColor()));
    connect(ui.maxColor, SIGNAL(clicked()), this, SLOT(setMaxColor()));
76

77
    // compute and draw the histogram
78
    ui.histogramGraphicsView->setScene(new QGraphicsScene(this));
79
80
    ui.histogramGraphicsView->setBackgroundBrush(QBrush(palette().window()));
    ui.histogramGraphicsView->setRenderHint(QPainter::Antialiasing);
81
82
83
}


84
//---------------------- destructor ----------------------------
85
ImageLutWidget::~ImageLutWidget() {
86
    delete greyLevels;
87
88
}

89
//---------------------- updateComponent ----------------------------
90
void ImageLutWidget::updateComponent(ImageComponent* comp) {
91

92
    myComponent = comp;
93

94
    // if there is no lookup table, just don't display this widget!
Emmanuel Promayon's avatar
Emmanuel Promayon committed
95
    if (myComponent->getLut() == nullptr) {
96
97
        setEnabled(false);
        return;
98
99
    }
    else {
100
101
        setEnabled(true);
    }
102

103
    invert = false;
104

105
    // initialize the sliders value
106
    double* imgRange = myComponent->getImageData()->GetScalarRange();
saubatn's avatar
saubatn committed
107
108
109
    double imgMinColor = imgRange[0];
    double imgMaxColor = imgRange[1];
    double nbColorsOrg = imgMaxColor - imgMinColor;
110
    auto nbOfColors = (long int)(nbColorsOrg);
111

112
    // as this widget is only grayscale, compute the average of the color values
saubatn's avatar
saubatn committed
113
114
115
116
    lutMin = imgMinColor;
    lutMax = imgMaxColor;

    // update scale and table value information on the luts
117
    if ((unsigned)abs(lutMax - lutMin) > UINT_MAX) {
118
        nbHistoBins = UINT_MAX;
119
120
    }
    else {
121
        nbHistoBins = abs(lutMax - lutMin);
122
    }
saubatn's avatar
saubatn committed
123
    myComponent->getLut()->SetNumberOfTableValues(nbHistoBins);
124

125
    blockAllSignals(true);
126
    initLevelGUI(lutMin, lutMax, myComponent->getLut()->GetLevel());
127
    initWindowGUI(0, myComponent->getLut()->GetWindow(), myComponent->getLut()->GetWindow());
128

saubatn's avatar
saubatn committed
129
130
    // allocate memory to draw the histogram according to the number of available scalar component
    // free memory of previously drawn histogram if the lut widget handle another component
131
    if (greyLevels) {
saubatn's avatar
saubatn committed
132
        delete greyLevels;
133
    }
saubatn's avatar
saubatn committed
134
135

    // allocate the memory needed for that component
136
    greyLevels = new double[nbHistoBins + 1];
saubatn's avatar
saubatn committed
137

138
    // check alpha state for min and max
139
    double* color = myComponent->getLut()->GetTableValue(0);
140
141
142
143
144
145
146
147
148
149
150
151
    QColor minColor = QColor::fromRgbF(color[0], color[1], color[2], 1.0);
    ui.minColor->setPalette(QPalette(minColor));
    ui.minTransparency->setChecked((color[3] < 1e-5));
    color = myComponent->getLut()->GetTableValue(nbOfColors - 1);
    QColor maxColor = QColor::fromRgbF(color[0], color[1], color[2], 1.0);
    ui.maxColor->setPalette(QPalette(maxColor));
    ui.maxTransparency->setChecked((color[3] < 1e-5));

    // color scale brush
    updateGradient();

    // check inversion: if max color is not all black, take the min color
152
    if (color[0] * 255.0 < 1.0 && color[1] * 255 < 1.0 && color[2] * 255 < 1.0) {
153
154
155
        color = myComponent->getLut()->GetTableValue(0);
        invert = true;
    }
156
    blockAllSignals(false);
157

158
159
    // compute and draw the histogram
    applyLUT();
160
161
}

162
163
//---------------------- updateLUT ------------------------
void ImageLutWidget::applyLUT() {
saubatn's avatar
saubatn committed
164
165

    // set window level and width according to user set up
166
167
    myComponent->getLut()->SetWindow(ui.lineEditLutWindow->text().toInt());
    myComponent->getLut()->SetLevel(ui.lineEditLutLevel->text().toInt());
168
169
170
171
172
173
174
175
176

    // use the color to update table values
    int nbOfColors = myComponent->getLut()->GetNumberOfTableValues();
    QColor fadedColor = ui.minColor->palette().button().color();
    QColor strongColor = ui.maxColor->palette().button().color();
    QColor maxColor, minColor;
    if (!invert) {
        minColor = fadedColor;
        maxColor = strongColor;
177
178
    }
    else {
179
180
181
182
183
184
185
        minColor = strongColor;
        maxColor = fadedColor;
    }
    myComponent->getLut()->SetMinimumTableValue(minColor.redF(), minColor.greenF(), minColor.blueF(), 1.0);
    myComponent->getLut()->SetMaximumTableValue(maxColor.redF(), maxColor.greenF(), maxColor.blueF(), 1.0);
    // build using the given range
    myComponent->getLut()->Build();
186

187
188
189
    // once the whole colors are build change the min/max color alpha
    myComponent->getLut()->SetTableValue(0, minColor.redF(), minColor.greenF(), minColor.blueF(), (ui.minTransparency->isChecked() ? 0.0 : 1.0));
    myComponent->getLut()->SetTableValue(nbOfColors - 1, maxColor.redF(), maxColor.greenF(), maxColor.blueF(), (ui.maxTransparency->isChecked() ? 0.0 : 1.0));
190

191
    myComponent->refresh();
saubatn's avatar
saubatn committed
192

193
194
    draw();
}
195
196

//---------------------- resetLut ------------------------
197
void ImageLutWidget::resetLUT() {
198
    // init all palette values
199
    blockAllSignals(true);
200
201
    initLevelGUI(lutMin, lutMax, int ((lutMax - lutMin) / 2.0));
    initWindowGUI(0, (lutMax - lutMin), lutMax - lutMin);
202
    invert = false;
203

204
205
    ui.maxTransparency->setChecked(false);
    ui.minTransparency->setChecked(false);
206

207
208
209
    ui.minColor->setPalette(QPalette(Qt::black));
    ui.maxColor->setPalette(QPalette(Qt::white));
    blockAllSignals(false);
210
211

    // update palette color applied to the images and the histogram
212
    applyLUT();
213
214
}

215
//---------------------- draw ------------------------
216
void ImageLutWidget::draw() {
saubatn's avatar
saubatn committed
217

218
    //-- initialize histogram values to 0
219
    for (unsigned int i = 0; i < nbHistoBins; i++) {
220
        greyLevels[i] = 0.0;
221
    }
222

223
224
    //-- get image volume
    vtkSmartPointer<vtkImageData> data;
225
    if (myComponent) {
226
        data = myComponent->getImageData();
227
228
    }
    else {
229
        data = vtkSmartPointer<vtkImageData>::New();
230
    }
231
232

    //-- image dimensions
233
    int* dims = data->GetDimensions();
234
235
    unsigned int totalDim = dims[0] * dims[1] * dims[2];

236
    //-- computate the histogram given the value data type
237
    switch (data->GetScalarType()) {
238
239
240
241
242
243
244
245
        default:
        case VTK_ID_TYPE:
        case VTK_BIT:
        case VTK_LONG:
        case VTK_UNSIGNED_LONG:
            break;
        case VTK_CHAR:
        case VTK_SIGNED_CHAR:
246
247
            fillHistogramTable<char> ((char*) data->GetScalarPointer(), totalDim,
                                      (char) lutMin, (char) lutMax);
248
249
            break;
        case VTK_UNSIGNED_CHAR:
250
251
            fillHistogramTable<unsigned char> ((unsigned char*) data->GetScalarPointer(), totalDim,
                                               (unsigned char) lutMin, (unsigned char) lutMax);
252
253
            break;
        case VTK_SHORT:
254
255
            fillHistogramTable<short> ((short*) data->GetScalarPointer(), totalDim,
                                       (short) lutMin, (short) lutMax);
256
257
            break;
        case VTK_UNSIGNED_SHORT:
258
259
            fillHistogramTable<unsigned short> ((unsigned short*) data->GetScalarPointer(), totalDim,
                                                (unsigned short) lutMin, (unsigned short) lutMax);
260
261
            break;
        case VTK_INT:
262
263
            fillHistogramTable<int> ((int*) data->GetScalarPointer(), totalDim,
                                     (int) lutMin, (int) lutMax);
264
265
            break;
        case VTK_UNSIGNED_INT:
266
267
            fillHistogramTable<unsigned int> ((unsigned int*) data->GetScalarPointer(), totalDim,
                                              (unsigned int) lutMin, (unsigned int) lutMax);
268
269
            break;
        case VTK_FLOAT:
270
271
            fillHistogramTable<float> ((float*) data->GetScalarPointer(), totalDim,
                                       (float) lutMin, (float) lutMax);
272
273
            break;
        case VTK_DOUBLE:
274
275
            fillHistogramTable<double> ((double*) data->GetScalarPointer(), totalDim,
                                        (double) lutMin, (double) lutMax);
276
            break;
277
278
    }

279
280
    //-- prepare draw
    ui.histogramGraphicsView->scene()->clear();
281
    QPen pen;
282
283
284
285
    pen.setWidth(1);
    pen.setColor(palette().background().color());

    //-- background color
286
    // Scaling the graphic view is needed: in case highestGreyLevel is greater than max int on Win 32bits
287
288
    // Qt paint canvas bug crashes. When using Qt5, try to remove the scaling code to see if the bug has been fixed.
    double defaultHeight = 256.0;
289
    double scalingFactor = defaultHeight / highestGreyLevel;
290
    QRectF sceneRectangle(lutMin, 0.0, nbHistoBins, defaultHeight);
291
292
293
294

    //-- draw color table
    QLinearGradient colorGradient(sceneRectangle.x(), sceneRectangle.height() / 2.0, sceneRectangle.width(), sceneRectangle.height() / 2.0);
    int nbOfColors = myComponent->getLut()->GetNumberOfTableValues();
295
    double* color;
soniayukiselmi's avatar
soniayukiselmi committed
296
    for (int i = 0; i < nbOfColors; i++) {
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
        color = myComponent->getLut()->GetTableValue(i);
        colorGradient.setColorAt(double(i) / double(nbOfColors), QColor::fromRgbF(color[0], color[1], color[2]));
    }
    QBrush gradientBrush(colorGradient);
    sceneRectItem = new QGraphicsRectItem(sceneRectangle);
    sceneRectItem->setPen(pen);
    sceneRectItem->setBrush(gradientBrush);
    ui.histogramGraphicsView->scene()->addItem(sceneRectItem);

    //-- show transparency
    double window = myComponent->getLut()->GetWindow();
    double level = myComponent->getLut()->GetLevel();
    if (ui.maxTransparency->isChecked()) {
        QPointF maxCorner(sceneRectangle.x() + level + window / 2.0, sceneRectangle.y());
        if (maxCorner.x() < sceneRectangle.width()) {
            ui.histogramGraphicsView->scene()->addRect(maxCorner.x(), maxCorner.y(), sceneRectangle.width() - maxCorner.x(), sceneRectangle.height(), pen, QBrush(palette().window()));
        }
    }
    if (ui.minTransparency->isChecked()) {
        QPointF minCorner(sceneRectangle.x() + level - window / 2.0, sceneRectangle.y());
        if (minCorner.x() > sceneRectangle.x()) {
            ui.histogramGraphicsView->scene()->addRect(sceneRectangle.x(), sceneRectangle.y(), minCorner.x(), sceneRectangle.height(), pen, QBrush(palette().window()));
        }
320
321
    }

322
    //-- draw histogram
saubatn's avatar
saubatn committed
323
324
    qreal barHeight;
    qreal barWidth = 1.0; //sceneRectangle.width() / double(nbHistoBins);
325
326
    double x = sceneRectangle.x();
    QPainterPath histogramPath(QPointF(x, sceneRectangle.height()));
327
    for (unsigned int i = 0; i < nbHistoBins; i++) {
328
        barHeight = greyLevels[i] * scalingFactor;
329
330
331
332
333
334
        histogramPath.lineTo(x, sceneRectangle.height() - barHeight);
        x += barWidth;
    }
    histogramPath.lineTo(sceneRectangle.width(), sceneRectangle.height());
    histogramPath.lineTo(x, sceneRectangle.height());
    pen.setColor(Qt::white);
saubatn's avatar
saubatn committed
335
    ui.histogramGraphicsView->scene()->addPath(histogramPath, pen, Qt::blue);
336
337
338
339

    //-- draw lut level and window
    pen.setColor(Qt::darkGreen);
    pen.setStyle(Qt::DashLine);
saubatn's avatar
saubatn committed
340
341

    // pen width depends on numbers of bars in the histogram
342
    int penWidth = 3.0; // (int)(sceneRectangle.width() / 100.0);
saubatn's avatar
saubatn committed
343
344
    pen.setWidth(penWidth);

345
346
347
348
    ui.histogramGraphicsView->scene()->addLine(level, sceneRectangle.y(), level, sceneRectangle.height(), pen);

    pen.setStyle(Qt::SolidLine);
    // create the proper path for the LUT
saubatn's avatar
saubatn committed
349
350
    QPointF leftCorner(level - window / 2.0, sceneRectangle.height());
    QPointF rightCorner(level + window / 2.0, sceneRectangle.y());
351
    QPainterPath path;
saubatn's avatar
saubatn committed
352
353
354
355
356
357
    path.moveTo(sceneRectangle.x(), sceneRectangle.height());
    path.lineTo(leftCorner);
    path.lineTo(rightCorner);
    path.lineTo(sceneRectangle.width(), sceneRectangle.y());

    pen.setWidth(penWidth);
358
    ui.histogramGraphicsView->scene()->addPath(path, pen);
359

360
361
    //-- fit all in viewer
    fitView();
362
363
364
365
}


//---------------------- fillHistogramTable ------------------------
366
template<class DATATYPE>
367
void ImageLutWidget::fillHistogramTable(DATATYPE* data, unsigned int dataDim, DATATYPE minVal, DATATYPE maxVal) {
368

369
    if (((DATATYPE)nbHistoBins) == 0) {
370
        CAMITK_ERROR(tr("Number of bins is equals to zero."))
371
372
    }

saubatn's avatar
saubatn committed
373
    // scale factor from [min,max] to [0..nbHistoBins]
374
    auto intervalLength = (DATATYPE)((maxVal - minVal) / (DATATYPE)nbHistoBins);
375

376
    if (intervalLength != 0) {
377
        //-- build histogram
378
        for (unsigned int i = 0; i < dataDim; i++) {
379
            // Find the corresponding interval index
380
            auto pointIndex = (unsigned int)((data[i] - minVal) / intervalLength);
381
382
383
            // build the histogram (increment the corresponding value)
            greyLevels[pointIndex] += 1.0;
        }
384

385
386
        //-- compute max value
        highestGreyLevel = 0;
387
        for (unsigned int i = 0; i < nbHistoBins; i++) {
388
            if (greyLevels[i] > highestGreyLevel) {
389
                highestGreyLevel = greyLevels[i];
390
            }
391
        }
392
393
    }
    else {
394
        CAMITK_ERROR(tr("Not enough levels in the image, level in [%1,%2]").arg(QString::number(minVal), QString::number(maxVal)))
saubatn's avatar
saubatn committed
395
    }
396
397
}

398
//---------------------- resizeEvent  ----------------------------
399
void ImageLutWidget::resizeEvent(QResizeEvent*) {
400
401
    fitView();
}
402

403
//---------------------- showEvent  ----------------------------
404
void ImageLutWidget::showEvent(QShowEvent*) {
405
406
    fitView();
}
407

408
409
410
411
412
413
//---------------------- fitView  ----------------------------
void ImageLutWidget::fitView() {
    ui.histogramGraphicsView->fitInView(sceneRectItem);
    ui.histogramGraphicsView->centerOn(sceneRectItem->rect().center());
    ui.histogramGraphicsView->setSceneRect(sceneRectItem->rect());
}
414

415
416
417
418
//---------------------- initLevelGUI  ----------------------------
void ImageLutWidget::initLevelGUI(int min, int max, int value) {
    initSlider(ui.sliderLutLevel, min, max, value);
    // add validator for the slide range
419
    QValidator* validator = new QIntValidator(min, max, this);
420
    ui.lineEditLutLevel->setValidator(validator);
421
    ui.lineEditLutLevel->setText(QString::number(value));
422
}
423

424
425
426
427
//---------------------- initWindowGUI  ----------------------------
void ImageLutWidget::initWindowGUI(int min, int max, int value) {
    initSlider(ui.sliderLutWindow, min, max, value);
    // add validator for the slide range
428
    QValidator* validator = new QIntValidator(min, max, this);
429
    ui.lineEditLutWindow->setValidator(validator);
430
    ui.lineEditLutWindow->setText(QString::number(value));
431
}
432

433
//---------------------- initSlider  ----------------------------
434
void ImageLutWidget::initSlider(QSlider* slider, int min, int max, int value) {
435
    // set slider range
436
    slider->setRange(min, max);
437
    // current value
438
    slider->setValue(value);
439
440
    // set steps
    int range = max - min;
441
442
    slider->setSingleStep(range / 100);
    slider->setPageStep(range / 10);
443
}
444

445
446
447
// ---------------------- lineEditLUTLevelChanged  ----------------------------
void ImageLutWidget::lineEditLUTLevelChanged() {
    // update slider value
448
449
450
    blockAllSignals(true);
    ui.sliderLutLevel->setValue(ui.lineEditLutLevel->text().toInt());
    blockAllSignals(false);
451

452
453
454
    // update palette color applied to the images and the histogram
    applyLUT();
}
455

456
// ---------------------- sliderLUTLevelChanged  ----------------------------
457
void ImageLutWidget::sliderLUTLevelChanged(int level) {
458
    // update line edit text
459
460
461
    blockAllSignals(true);
    ui.lineEditLutLevel->setText(QString::number(level));
    blockAllSignals(false);
462

463
464
465
    // update palette color applied to the images and the histogram
    applyLUT();
}
466

467
468
469
// ---------------------- sliderLUTWindowChanged  ----------------------------
void ImageLutWidget::sliderLUTWindowChanged(int window) {
    // update slider value
470
471
472
    blockAllSignals(true);
    ui.lineEditLutWindow->setText(QString::number(window));
    blockAllSignals(false);
473

474
475
476
477
478
    // update palette color applied to the images and the histogram
    applyLUT();
}

// ---------------------- lineEditLUTWindowChanged  ----------------------------
479
void ImageLutWidget::lineEditLUTWindowChanged() {
480
481
    // update line edit text
    blockAllSignals(true);
482
    ui.sliderLutWindow->setValue(ui.lineEditLutWindow->text().toInt());
483
    blockAllSignals(false);
484

485
486
487
    // update palette color applied to the images and the histogram
    applyLUT();
}
488

489
490
491
492
// ---------------------- invertButtonClicked  ----------------------------
void ImageLutWidget::invertButtonClicked() {
    invert = !invert;
    applyLUT();
saubatn's avatar
saubatn committed
493
494
495
496
497
    /*    QColor maxColor = ui.maxColor->palette().button().color();
        QColor minColor = ui.minColor->palette().button().color();
        ui.maxColor->setPalette(QPalette(minColor));
        ui.minColor->setPalette(QPalette(maxColor));
        */
498
499
    updateGradient();
}
500

501
502
503
504
// ---------------------- updateGradient  ----------------------------
void ImageLutWidget::updateGradient() {
    QColor maxColor = ui.maxColor->palette().button().color();
    QColor minColor = ui.minColor->palette().button().color();
505
    QString style = "background-color: qlineargradient(x1:0 y1:0, x2:1 y2:0, stop:0 rgba(" +
506
507
508
509
510
511
512
513
                    QString::number(minColor.red()) + ", " +
                    QString::number(minColor.green()) + ", " +
                    QString::number(minColor.blue()) + ", " +
                    QString::number(minColor.alpha()) + " ), stop:1 rgba( " +
                    QString::number(maxColor.red()) + ", " +
                    QString::number(maxColor.green()) + ", " +
                    QString::number(maxColor.blue()) + ", " +
                    QString::number(maxColor.alpha()) + " ) )";
514
515
    ui.colorScale->setStyleSheet(style);
}
516

517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
// ---------------------- setMaxColor ----------------------------
void ImageLutWidget::setMaxColor() {
    QColor oldColor = ui.maxColor->palette().button().color();
    QColor maxColor = QColorDialog::getColor(oldColor, this, "Max color");

    ui.maxColor->setPalette(QPalette(maxColor));
    updateGradient();
    applyLUT();
}

// ---------------------- setMinColor ----------------------------
void ImageLutWidget::setMinColor() {
    QColor oldColor = ui.minColor->palette().button().color();
    QColor minColor = QColorDialog::getColor(oldColor, this, "Max color");

    ui.minColor->setPalette(QPalette(minColor));
    updateGradient();
    applyLUT();
}

// ---------------------- blockAllSignals ----------------------------
void ImageLutWidget::blockAllSignals(bool block) {
    ui.sliderLutLevel->blockSignals(block);
    ui.sliderLutWindow->blockSignals(block);
    ui.lineEditLutLevel->blockSignals(block);
    ui.lineEditLutWindow->blockSignals(block);
    ui.maxTransparency->blockSignals(block);
    ui.minTransparency->blockSignals(block);
    ui.inversion->blockSignals(block);
    ui.resetLut->blockSignals(block);
    ui.minColor->blockSignals(block);
    ui.maxColor->blockSignals(block);
}
550