<commit_before>/*=========================================================================

Program:   Medical Imaging & Interaction Toolkit
Module:    $RCSfile$
Language:  C++
Date:      $Date$
Version:   $Revision$

Copyright (c) German Cancer Research Center, Division of Medical and
Biological Informatics. All rights reserved.
See MITKCopyright.txt or http://www.mitk.org/copyright.html for details.

This software is distributed WITHOUT ANY WARRANTY; without even
the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
PURPOSE.  See the above copyright notices for more information.

=========================================================================*/


#include "mitkLevelWindow.h"
#include "mitkImageSliceSelector.h"

#include <ipFunc/ipFunc.h>
#include <algorithm>

mitk::LevelWindow::LevelWindow(mitk::ScalarType level, mitk::ScalarType window) : m_Min(level-window/2.0), m_Max(level+window/2.0), m_RangeMin(-2048), m_RangeMax(4096)
{

}

mitk::LevelWindow::LevelWindow(const mitk::LevelWindow& levWin)
{
  *this=levWin;
}

mitk::LevelWindow::~LevelWindow()
{
}

mitk::ScalarType mitk::LevelWindow::GetLevel() const
{
  return (m_Max-m_Min)/2.0 + m_Min;
}

mitk::ScalarType mitk::LevelWindow::GetWindow() const
{
  return (m_Max-m_Min);
}

mitk::ScalarType mitk::LevelWindow::GetMin() const
{
  return m_Min;
}

mitk::ScalarType mitk::LevelWindow::GetMax() const
{
  return m_Max;
}

void mitk::LevelWindow::SetLevel(mitk::ScalarType level)
{
  mitk::ScalarType halfWindow = (m_Max - m_Min) / 2;
  m_Min = level - halfWindow;
  m_Max = level + halfWindow;

  testValues();
}

void mitk::LevelWindow::SetWindow(mitk::ScalarType window)
{
  mitk::ScalarType level = m_Min + (m_Max - m_Min) / 2;
  mitk::ScalarType halfWindow = window / 2;

  m_Min = level - halfWindow;
  m_Max = level + halfWindow;

  testValues();
}

void mitk::LevelWindow::SetLevelWindow(mitk::ScalarType level, mitk::ScalarType window)
{
  m_Min = level - window / 2.0;
  m_Max = level + window / 2.0;

  testValues();
}

void mitk::LevelWindow::SetMin(mitk::ScalarType min)
{
  m_Min = min;
  testValues(); 
}

void mitk::LevelWindow::SetMax(mitk::ScalarType max)
{
  m_Max = max;
  testValues();
}

void mitk::LevelWindow::SetMinMax(mitk::ScalarType min, mitk::ScalarType max)
{
  if(min>max)
    std::swap(min,max);

  SetMin(min);
  SetMax(max);
}

void mitk::LevelWindow::SetRangeMin(mitk::ScalarType min)
{
  m_RangeMin = min;
  if(m_RangeMin > m_RangeMax)
    std::swap(m_RangeMin,m_RangeMax);
  testValues();
}

void mitk::LevelWindow::SetRangeMax(mitk::ScalarType max)
{
  m_RangeMax = max;
  if(m_RangeMin > m_RangeMax)
    std::swap(m_RangeMin,m_RangeMax);
  testValues();
}

mitk::ScalarType mitk::LevelWindow::GetRangeMin() const
{
  return m_RangeMin;
}

mitk::ScalarType mitk::LevelWindow::GetRangeMax() const
{
  return m_RangeMax;
}

mitk::ScalarType mitk::LevelWindow::GetRange() const
{
  return  m_RangeMax - m_RangeMin;
}

/*!
This method initializes a mitk::LevelWindow from an mitk::Image. The algorithm is as follows:
  
Default to taking the central image slice for quick analysis.

Compute the smallest (minValue), second smallest (min2ndValue), second largest (max2ndValue), and
largest (maxValue) data value by traversing the pixel values only once. In the
same scan it also computes the count of minValue values and maxValue values.
After that a basic histogram with specific information about the
extrems is complete.

If minValue == maxValue, the center slice is uniform and the above scan is repeated for
the complete image, not just one slice

Next, special cases of images with only 1, 2 or 3 distinct data values
have hand assigned level window ranges.

Next the level window is set relative to the inner range IR = lengthOf([min2ndValue, max2ndValue])

For count(minValue) > 20% the smallest values are frequent and should be
distinct from the min2ndValue and larger values (minValue may be std:min, may signify
something special) hence the lower end of the level window is set to min2ndValue - 0.5 * IR
 
For count(minValue) <= 20% the smallest values are not so important and can
blend with the next ones => min(level window) = min2ndValue

And analog for max(level window):
count(max2ndValue) > 20%:  max(level window) = max2ndValue + 0.5 * IR
count(max2ndValue) < 20%:  max(level window) = max2ndValue

In both 20%+ cases the level window bounds are clamped to the [minValue, maxValue] range

In consequence the level window maximizes contrast with minimal amount of
computation and does do useful things if the data contains std::min or
std:max values or has only 1 or 2 or 3 data values.
*/
void mitk::LevelWindow::SetAuto(mitk::Image* image, bool tryPicTags, bool guessByCentralSlice)
{
    if ( image == NULL )
        return;

    if ( tryPicTags )
    {
        if ( SetAutoByPicTags(image->GetPic()) )
            return;
    }

    mitk::Image* wholeImage = image;
    mitk::ImageSliceSelector::Pointer sliceSelector = mitk::ImageSliceSelector::New();
    if ( guessByCentralSlice )
    {
        sliceSelector->SetInput(image);
        sliceSelector->SetSliceNr(image->GetDimension(2)/2);
        sliceSelector->SetTimeNr(image->GetDimension(3)/2);
        sliceSelector->SetChannelNr(image->GetDimension(4)/2);
        sliceSelector->Update();<commit_msg>FIX: bug #27: mitk::DataTreeNodeFactory::SetDefaultImageProperties calls LevelWindow::SetAuto on the image starting with rev 1.84, which accesses the image. In the case of the bug, the image was not yet initialized. Resolution: check for IsInitialized in LevelWindow::SetAuto<commit_after>/*=========================================================================

Program:   Medical Imaging & Interaction Toolkit
Module:    $RCSfile$
Language:  C++
Date:      $Date$
Version:   $Revision$

Copyright (c) German Cancer Research Center, Division of Medical and
Biological Informatics. All rights reserved.
See MITKCopyright.txt or http://www.mitk.org/copyright.html for details.

This software is distributed WITHOUT ANY WARRANTY; without even
the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
PURPOSE.  See the above copyright notices for more information.

=========================================================================*/


#include "mitkLevelWindow.h"
#include "mitkImageSliceSelector.h"

#include <ipFunc/ipFunc.h>
#include <algorithm>

mitk::LevelWindow::LevelWindow(mitk::ScalarType level, mitk::ScalarType window) : m_Min(level-window/2.0), m_Max(level+window/2.0), m_RangeMin(-2048), m_RangeMax(4096)
{

}

mitk::LevelWindow::LevelWindow(const mitk::LevelWindow& levWin)
{
  *this=levWin;
}

mitk::LevelWindow::~LevelWindow()
{
}

mitk::ScalarType mitk::LevelWindow::GetLevel() const
{
  return (m_Max-m_Min)/2.0 + m_Min;
}

mitk::ScalarType mitk::LevelWindow::GetWindow() const
{
  return (m_Max-m_Min);
}

mitk::ScalarType mitk::LevelWindow::GetMin() const
{
  return m_Min;
}

mitk::ScalarType mitk::LevelWindow::GetMax() const
{
  return m_Max;
}

void mitk::LevelWindow::SetLevel(mitk::ScalarType level)
{
  mitk::ScalarType halfWindow = (m_Max - m_Min) / 2;
  m_Min = level - halfWindow;
  m_Max = level + halfWindow;

  testValues();
}

void mitk::LevelWindow::SetWindow(mitk::ScalarType window)
{
  mitk::ScalarType level = m_Min + (m_Max - m_Min) / 2;
  mitk::ScalarType halfWindow = window / 2;

  m_Min = level - halfWindow;
  m_Max = level + halfWindow;

  testValues();
}

void mitk::LevelWindow::SetLevelWindow(mitk::ScalarType level, mitk::ScalarType window)
{
  m_Min = level - window / 2.0;
  m_Max = level + window / 2.0;

  testValues();
}

void mitk::LevelWindow::SetMin(mitk::ScalarType min)
{
  m_Min = min;
  testValues(); 
}

void mitk::LevelWindow::SetMax(mitk::ScalarType max)
{
  m_Max = max;
  testValues();
}

void mitk::LevelWindow::SetMinMax(mitk::ScalarType min, mitk::ScalarType max)
{
  if(min>max)
    std::swap(min,max);

  SetMin(min);
  SetMax(max);
}

void mitk::LevelWindow::SetRangeMin(mitk::ScalarType min)
{
  m_RangeMin = min;
  if(m_RangeMin > m_RangeMax)
    std::swap(m_RangeMin,m_RangeMax);
  testValues();
}

void mitk::LevelWindow::SetRangeMax(mitk::ScalarType max)
{
  m_RangeMax = max;
  if(m_RangeMin > m_RangeMax)
    std::swap(m_RangeMin,m_RangeMax);
  testValues();
}

mitk::ScalarType mitk::LevelWindow::GetRangeMin() const
{
  return m_RangeMin;
}

mitk::ScalarType mitk::LevelWindow::GetRangeMax() const
{
  return m_RangeMax;
}

mitk::ScalarType mitk::LevelWindow::GetRange() const
{
  return  m_RangeMax - m_RangeMin;
}

/*!
This method initializes a mitk::LevelWindow from an mitk::Image. The algorithm is as follows:
  
Default to taking the central image slice for quick analysis.

Compute the smallest (minValue), second smallest (min2ndValue), second largest (max2ndValue), and
largest (maxValue) data value by traversing the pixel values only once. In the
same scan it also computes the count of minValue values and maxValue values.
After that a basic histogram with specific information about the
extrems is complete.

If minValue == maxValue, the center slice is uniform and the above scan is repeated for
the complete image, not just one slice

Next, special cases of images with only 1, 2 or 3 distinct data values
have hand assigned level window ranges.

Next the level window is set relative to the inner range IR = lengthOf([min2ndValue, max2ndValue])

For count(minValue) > 20% the smallest values are frequent and should be
distinct from the min2ndValue and larger values (minValue may be std:min, may signify
something special) hence the lower end of the level window is set to min2ndValue - 0.5 * IR
 
For count(minValue) <= 20% the smallest values are not so important and can
blend with the next ones => min(level window) = min2ndValue

And analog for max(level window):
count(max2ndValue) > 20%:  max(level window) = max2ndValue + 0.5 * IR
count(max2ndValue) < 20%:  max(level window) = max2ndValue

In both 20%+ cases the level window bounds are clamped to the [minValue, maxValue] range

In consequence the level window maximizes contrast with minimal amount of
computation and does do useful things if the data contains std::min or
std:max values or has only 1 or 2 or 3 data values.
*/
void mitk::LevelWindow::SetAuto(mitk::Image* image, bool tryPicTags, bool guessByCentralSlice)
{
    if ( ( image == NULL ) || ( !image->IsInitialized()) )
        return;

    if ( tryPicTags )
    {
        if ( SetAutoByPicTags(image->GetPic()) )
            return;
    }

    mitk::Image* wholeImage = image;
    mitk::ImageSliceSelector::Pointer sliceSelector = mitk::ImageSliceSelector::New();
    if ( guessByCentralSlice )
    {
        sliceSelector->SetInput(image);
        sliceSelector->SetSliceNr(image->GetDimension(2)/2);
        sliceSelector->SetTimeNr(image->GetDimension(3)/2);
        sliceSelector->SetChannelNr(image->GetDimension(4)/2);
        sliceSelector->Update();
{'fraction_non_alphanumeric': 0.13366336633663367, 'fraction_numerical': 0.011092775944261092, 'mean_word_length': 4.903138528138528, 'pattern_counts': {'":': 0, '<': 11, '<?xml version=': 0, '>': 38, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '1996069', 'n_tokens_mistral': 3532, 'n_tokens_neox': 3425, 'n_words': 1022}