You can not select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
		
			
		
			
				
					
					
						
							440 lines
						
					
					
						
							9.8 KiB
						
					
					
				
			
		
		
		
			
			
			
		
		
	
	
							440 lines
						
					
					
						
							9.8 KiB
						
					
					
				
								/*
							 | 
						|
								 * This program source code file is part of KiCad, a free EDA CAD application.
							 | 
						|
								 *
							 | 
						|
								 * Copyright (C) 2015 Mario Luzeiro <mrluzeiro@gmail.com>
							 | 
						|
								 * Copyright (C) 1992-2015 KiCad Developers, see AUTHORS.txt for contributors.
							 | 
						|
								 *
							 | 
						|
								 * This program is free software; you can redistribute it and/or
							 | 
						|
								 * modify it under the terms of the GNU General Public License
							 | 
						|
								 * as published by the Free Software Foundation; either version 2
							 | 
						|
								 * of the License, or (at your option) any later version.
							 | 
						|
								 *
							 | 
						|
								 * This program 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 General Public License for more details.
							 | 
						|
								 *
							 | 
						|
								 * You should have received a copy of the GNU General Public License
							 | 
						|
								 * along with this program; if not, you may find one here:
							 | 
						|
								 * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
							 | 
						|
								 * or you may search the http://www.gnu.org website for the version 2 license,
							 | 
						|
								 * or you may write to the Free Software Foundation, Inc.,
							 | 
						|
								 * 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
							 | 
						|
								 */
							 | 
						|
								
							 | 
						|
								 /**
							 | 
						|
								 * @file CImage.cpp
							 | 
						|
								 * @brief one 8bit-channel image implementation
							 | 
						|
								 */
							 | 
						|
								
							 | 
						|
								#include "CImage.h"
							 | 
						|
								#include <wx/image.h>                                                           // Used for save an image to disk
							 | 
						|
								#include <string.h>                                                             // For memcpy
							 | 
						|
								
							 | 
						|
								#ifndef CLAMP
							 | 
						|
								#define CLAMP(n, min, max) {if (n < min) n=min; else if (n > max) n = max;}
							 | 
						|
								#endif
							 | 
						|
								
							 | 
						|
								
							 | 
						|
								CIMAGE::CIMAGE( unsigned int aXsize, unsigned int aYsize )
							 | 
						|
								{
							 | 
						|
								    m_wxh     = aXsize * aYsize;
							 | 
						|
								    m_pixels  = (unsigned char*)malloc( m_wxh );
							 | 
						|
								    m_width   = aXsize;
							 | 
						|
								    m_height  = aYsize;
							 | 
						|
								    m_wraping = (E_WRAP)WRAP_CLAMP;
							 | 
						|
								}
							 | 
						|
								
							 | 
						|
								
							 | 
						|
								CIMAGE::~CIMAGE()
							 | 
						|
								{
							 | 
						|
								    free( m_pixels );
							 | 
						|
								}
							 | 
						|
								
							 | 
						|
								
							 | 
						|
								unsigned char* CIMAGE::GetBuffer() const
							 | 
						|
								{
							 | 
						|
								    return m_pixels;
							 | 
						|
								}
							 | 
						|
								
							 | 
						|
								
							 | 
						|
								bool CIMAGE::wrapCoords( int *aXo, int *aYo ) const
							 | 
						|
								{
							 | 
						|
								    int x = *aXo;
							 | 
						|
								    int y = *aYo;
							 | 
						|
								
							 | 
						|
								    switch(m_wraping)
							 | 
						|
								    {
							 | 
						|
								    case WRAP_CLAMP:
							 | 
						|
								        x =  (x < 0 )?0:x;
							 | 
						|
								        x =  (x >= (int)(m_width - 1))?(m_width - 1):x;
							 | 
						|
								        y =  (y < 0)?0:y;
							 | 
						|
								        y =  (y >= (int)(m_height - 1))?(m_height - 1):y;
							 | 
						|
								        break;
							 | 
						|
								    case WRAP_WRAP:
							 | 
						|
								        x = (x < 0)?((m_width - 1)+x):x;
							 | 
						|
								        x = (x >= (int)(m_width - 1))?(x - m_width):x;
							 | 
						|
								        y = (y < 0)?((m_height - 1)+y):y;
							 | 
						|
								        y = (y >= (int)(m_height - 1))?(y - m_height):y;
							 | 
						|
								        break;
							 | 
						|
								    default:
							 | 
						|
								        break;
							 | 
						|
								    }
							 | 
						|
								
							 | 
						|
								    if( (x < 0) || (x >= (int)m_width) ||
							 | 
						|
								        (y < 0) || (y >= (int)m_height) )
							 | 
						|
								        return false;
							 | 
						|
								
							 | 
						|
								    *aXo = x;
							 | 
						|
								    *aYo = y;
							 | 
						|
								
							 | 
						|
								    return true;
							 | 
						|
								}
							 | 
						|
								
							 | 
						|
								
							 | 
						|
								void CIMAGE::Setpixel( int aX, int aY, unsigned char aValue )
							 | 
						|
								{
							 | 
						|
								    if( wrapCoords( &aX, &aY ) )
							 | 
						|
								        m_pixels[aX + aY * m_width] = aValue;
							 | 
						|
								}
							 | 
						|
								
							 | 
						|
								
							 | 
						|
								unsigned char CIMAGE::Getpixel( int aX, int aY ) const
							 | 
						|
								{
							 | 
						|
								    if( wrapCoords( &aX, &aY ) )
							 | 
						|
								        return m_pixels[aX + aY * m_width];
							 | 
						|
								    else
							 | 
						|
								        return 0;
							 | 
						|
								}
							 | 
						|
								
							 | 
						|
								
							 | 
						|
								void CIMAGE::Invert()
							 | 
						|
								{
							 | 
						|
								    for( unsigned int it = 0; it < m_wxh; it++ )
							 | 
						|
								        m_pixels[it] = 255 - m_pixels[it];
							 | 
						|
								}
							 | 
						|
								
							 | 
						|
								
							 | 
						|
								void CIMAGE::CopyFull( const CIMAGE *aImgA, const CIMAGE *aImgB, E_IMAGE_OP aOperation )
							 | 
						|
								{
							 | 
						|
								    int aV, bV;
							 | 
						|
								
							 | 
						|
								    if( aOperation == COPY_RAW )
							 | 
						|
								    {
							 | 
						|
								        if ( aImgA == NULL )
							 | 
						|
								            return;
							 | 
						|
								    }
							 | 
						|
								    else
							 | 
						|
								    {
							 | 
						|
								        if ( (aImgA == NULL) || (aImgB == NULL) )
							 | 
						|
								            return;
							 | 
						|
								    }
							 | 
						|
								
							 | 
						|
								    switch(aOperation)
							 | 
						|
								    {
							 | 
						|
								    case COPY_RAW:
							 | 
						|
								        memcpy( m_pixels, aImgA->m_pixels, m_wxh );
							 | 
						|
								    break;
							 | 
						|
								
							 | 
						|
								    case COPY_ADD:
							 | 
						|
								        for( unsigned int it = 0;it < m_wxh; it++ )
							 | 
						|
								        {
							 | 
						|
								            aV = aImgA->m_pixels[it];
							 | 
						|
								            bV = aImgB->m_pixels[it];
							 | 
						|
								
							 | 
						|
								            aV = (aV + bV);
							 | 
						|
								            aV = (aV > 255)?255:aV;
							 | 
						|
								
							 | 
						|
								            m_pixels[it] = aV;
							 | 
						|
								        }
							 | 
						|
								    break;
							 | 
						|
								
							 | 
						|
								    case COPY_SUB:
							 | 
						|
								        for( unsigned int it = 0;it < m_wxh; it++ )
							 | 
						|
								        {
							 | 
						|
								            aV = aImgA->m_pixels[it];
							 | 
						|
								            bV = aImgB->m_pixels[it];
							 | 
						|
								
							 | 
						|
								            aV = (aV - bV);
							 | 
						|
								            aV = (aV < 0)?0:aV;
							 | 
						|
								
							 | 
						|
								            m_pixels[it] = aV;
							 | 
						|
								        }
							 | 
						|
								    break;
							 | 
						|
								
							 | 
						|
								    case COPY_DIF:
							 | 
						|
								        for( unsigned int it = 0;it < m_wxh; it++ )
							 | 
						|
								        {
							 | 
						|
								            aV = aImgA->m_pixels[it];
							 | 
						|
								            bV = aImgB->m_pixels[it];
							 | 
						|
								
							 | 
						|
								            m_pixels[it] = abs(aV - bV);
							 | 
						|
								        }
							 | 
						|
								    break;
							 | 
						|
								
							 | 
						|
								    case COPY_MUL:
							 | 
						|
								        for( unsigned int it = 0;it < m_wxh; it++ )
							 | 
						|
								        {
							 | 
						|
								            aV = aImgA->m_pixels[it];
							 | 
						|
								            bV = aImgB->m_pixels[it];
							 | 
						|
								
							 | 
						|
								            m_pixels[it] = (unsigned char)((((float)aV / 255.0f) * ((float)bV / 255.0f)) * 255);
							 | 
						|
								        }
							 | 
						|
								    break;
							 | 
						|
								
							 | 
						|
								    case COPY_AND:
							 | 
						|
								        for( unsigned int it = 0;it < m_wxh; it++ )
							 | 
						|
								        {
							 | 
						|
								            m_pixels[it] = aImgA->m_pixels[it] & aImgB->m_pixels[it];
							 | 
						|
								        }
							 | 
						|
								    break;
							 | 
						|
								
							 | 
						|
								    case COPY_OR:
							 | 
						|
								        for( unsigned int it = 0;it < m_wxh; it++ )
							 | 
						|
								        {
							 | 
						|
								            m_pixels[it] = aImgA->m_pixels[it] | aImgB->m_pixels[it];
							 | 
						|
								        }
							 | 
						|
								    break;
							 | 
						|
								
							 | 
						|
								    case COPY_XOR:
							 | 
						|
								        for( unsigned int it = 0;it < m_wxh; it++ )
							 | 
						|
								        {
							 | 
						|
								            m_pixels[it] = aImgA->m_pixels[it] ^ aImgB->m_pixels[it];
							 | 
						|
								        }
							 | 
						|
								    break;
							 | 
						|
								
							 | 
						|
								    case COPY_BLEND50:
							 | 
						|
								        for( unsigned int it = 0;it < m_wxh; it++ )
							 | 
						|
								        {
							 | 
						|
								            aV = aImgA->m_pixels[it];
							 | 
						|
								            bV = aImgB->m_pixels[it];
							 | 
						|
								
							 | 
						|
								            m_pixels[it] = (aV + bV) / 2;
							 | 
						|
								        }
							 | 
						|
								    break;
							 | 
						|
								
							 | 
						|
								    case COPY_MIN:
							 | 
						|
								        for( unsigned int it = 0;it < m_wxh; it++ )
							 | 
						|
								        {
							 | 
						|
								            aV = aImgA->m_pixels[it];
							 | 
						|
								            bV = aImgB->m_pixels[it];
							 | 
						|
								
							 | 
						|
								            m_pixels[it] = (aV < bV)?aV:bV;
							 | 
						|
								        }
							 | 
						|
								    break;
							 | 
						|
								
							 | 
						|
								    case COPY_MAX:
							 | 
						|
								        for( unsigned int it = 0;it < m_wxh; it++ )
							 | 
						|
								        {
							 | 
						|
								            aV = aImgA->m_pixels[it];
							 | 
						|
								            bV = aImgB->m_pixels[it];
							 | 
						|
								
							 | 
						|
								            m_pixels[it] = (aV > bV)?aV:bV;
							 | 
						|
								        }
							 | 
						|
								    break;
							 | 
						|
								
							 | 
						|
								    default:
							 | 
						|
								    break;
							 | 
						|
								    }
							 | 
						|
								}
							 | 
						|
								
							 | 
						|
								// TIP: If you want create or test filters you can use GIMP
							 | 
						|
								// with a generic convolution matrix and get the values from there.
							 | 
						|
								// http://docs.gimp.org/nl/plug-in-convmatrix.html
							 | 
						|
								static const S_FILTER FILTERS[] =   {
							 | 
						|
								    // Hi Pass
							 | 
						|
								    {
							 | 
						|
								    {   { 0, -1, -1, -1,  0},
							 | 
						|
								        {-1,  2, -4,  2, -1},
							 | 
						|
								        {-1, -4, 13, -4, -1},
							 | 
						|
								        {-1,  2, -4,  2, -1},
							 | 
						|
								        { 0, -1, -1, -1,  0}
							 | 
						|
								    },
							 | 
						|
								        7,
							 | 
						|
								        255
							 | 
						|
								    },
							 | 
						|
								
							 | 
						|
								    // Blur
							 | 
						|
								    {
							 | 
						|
								    {   { 3,  5,  7,  5,  3},
							 | 
						|
								        { 5,  9, 12,  9,  5},
							 | 
						|
								        { 7, 12, 20, 12,  7},
							 | 
						|
								        { 5,  9, 12,  9,  5},
							 | 
						|
								        { 3,  5,  7,  5,  3}
							 | 
						|
								    },
							 | 
						|
								        182,
							 | 
						|
								        0
							 | 
						|
								    },
							 | 
						|
								
							 | 
						|
								    // Blur Invert
							 | 
						|
								    {
							 | 
						|
								    {   { 0,  0,  0,  0,  0},
							 | 
						|
								        { 0,  0, -1,  0,  0},
							 | 
						|
								        { 0, -1,  0, -1,  0},
							 | 
						|
								        { 0,  0, -1,  0,  0},
							 | 
						|
								        { 0,  0,  0,  0,  0}
							 | 
						|
								    },
							 | 
						|
								        4,
							 | 
						|
								        255
							 | 
						|
								    },
							 | 
						|
								
							 | 
						|
								    //
							 | 
						|
								    {
							 | 
						|
								    {   { 0,  2,  4,  2,  0},
							 | 
						|
								        { 2, -2,  1, -2,  2},
							 | 
						|
								        { 4,  1, -8,  1,  4},
							 | 
						|
								        { 2, -2,  1, -2,  2},
							 | 
						|
								        { 0,  2,  4,  2,  0}
							 | 
						|
								    },
							 | 
						|
								        20,
							 | 
						|
								        0
							 | 
						|
								    },
							 | 
						|
								
							 | 
						|
								    // Cartoon
							 | 
						|
								    {
							 | 
						|
								    {   {-1, -1, -1, -1,  0},
							 | 
						|
								        {-1,  0,  0,  0,  0},
							 | 
						|
								        {-1,  0,  4,  0,  0},
							 | 
						|
								        { 0,  0,  0,  1,  0},
							 | 
						|
								        { 0,  0,  0,  0,  4}
							 | 
						|
								    },
							 | 
						|
								        3,
							 | 
						|
								        0
							 | 
						|
								    },
							 | 
						|
								
							 | 
						|
								    // Emboss
							 | 
						|
								    {
							 | 
						|
								    {   {-1, -1, -1, -1,  0},
							 | 
						|
								        {-1, -1, -1,  0,  1},
							 | 
						|
								        {-1, -1,  0,  1,  1},
							 | 
						|
								        {-1,  0,  1,  1,  1},
							 | 
						|
								        { 0,  1,  1,  1,  1}
							 | 
						|
								    },
							 | 
						|
								        1,
							 | 
						|
								        128
							 | 
						|
								    },
							 | 
						|
								
							 | 
						|
								    // Sharpen
							 | 
						|
								    {
							 | 
						|
								    {   {-1, -1, -1, -1, -1},
							 | 
						|
								        {-1,  2,  2,  2, -1},
							 | 
						|
								        {-1,  2,  8,  2, -1},
							 | 
						|
								        {-1,  2,  2,  2, -1},
							 | 
						|
								        {-1, -1, -1, -1, -1}
							 | 
						|
								    },
							 | 
						|
								        8,
							 | 
						|
								        0
							 | 
						|
								    },
							 | 
						|
								
							 | 
						|
								    // Melt
							 | 
						|
								    {
							 | 
						|
								    {   { 4,  2,  6,  8,  1},
							 | 
						|
								        { 1,  2,  5,  4,  2},
							 | 
						|
								        { 0, -1,  1, -1,  0},
							 | 
						|
								        { 0,  0, -2,  0,  0},
							 | 
						|
								        { 0,  0,  0,  0,  0}
							 | 
						|
								    },
							 | 
						|
								        32,
							 | 
						|
								        0
							 | 
						|
								    },
							 | 
						|
								
							 | 
						|
								    // Sobel Gx
							 | 
						|
								    {
							 | 
						|
								    {   { 0,  0,  0,  0,  0},
							 | 
						|
								        { 0, -1,  0,  1,  0},
							 | 
						|
								        { 0, -2,  0,  2,  0},
							 | 
						|
								        { 0, -1,  0,  1,  0},
							 | 
						|
								        { 0,  0,  0,  0,  0}
							 | 
						|
								    },
							 | 
						|
								        1,
							 | 
						|
								        0
							 | 
						|
								    },
							 | 
						|
								
							 | 
						|
								    // Sobel Gy
							 | 
						|
								    {
							 | 
						|
								    {   { 1,  2,  4,  2,  1},
							 | 
						|
								        {-1, -1,  0,  1,  1},
							 | 
						|
								        {-2, -2,  0,  2,  2},
							 | 
						|
								        {-1, -1,  0,  1,  1},
							 | 
						|
								        {-1, -2, -4, -2, -1},
							 | 
						|
								    },
							 | 
						|
								        1,
							 | 
						|
								        0
							 | 
						|
								    }
							 | 
						|
								};// Filters
							 | 
						|
								
							 | 
						|
								
							 | 
						|
								//!TODO: This functions can be optimized slipting it between the edges and
							 | 
						|
								//       do it without use the getpixel function.
							 | 
						|
								//       Optimization can be done to m_pixels[ix + iy * m_width]
							 | 
						|
								//       but keep in mind the parallel process of the algorithm
							 | 
						|
								void CIMAGE::EfxFilter( CIMAGE *aInImg, E_FILTER aFilterType )
							 | 
						|
								{
							 | 
						|
								    S_FILTER filter = FILTERS[aFilterType];
							 | 
						|
								
							 | 
						|
								    aInImg->m_wraping = WRAP_CLAMP;
							 | 
						|
								    m_wraping = WRAP_CLAMP;
							 | 
						|
								
							 | 
						|
								    #ifdef USE_OPENMP
							 | 
						|
								    #pragma omp parallel for
							 | 
						|
								    #endif /* USE_OPENMP */
							 | 
						|
								
							 | 
						|
								    for( int iy = 0; iy < (int)m_height; iy++)
							 | 
						|
								    {
							 | 
						|
								        for( int ix = 0; ix < (int)m_width; ix++ )
							 | 
						|
								        {
							 | 
						|
								            int v = 0;
							 | 
						|
								
							 | 
						|
								            for( int sy = 0; sy < 5; sy++ )
							 | 
						|
								            {
							 | 
						|
								                for( int sx = 0; sx < 5; sx++ )
							 | 
						|
								                {
							 | 
						|
								                    int factor = filter.kernel[sx][sy];
							 | 
						|
								                    unsigned char pixelv = aInImg->Getpixel( ix + sx - 2, iy + sy - 2 );
							 | 
						|
								                    v += pixelv * factor;
							 | 
						|
								                }
							 | 
						|
								            }
							 | 
						|
								
							 | 
						|
								            v /= filter.div;
							 | 
						|
								
							 | 
						|
								            v += filter.offset;
							 | 
						|
								
							 | 
						|
								            CLAMP(v, 0, 255);
							 | 
						|
								
							 | 
						|
								            m_pixels[ix + iy * m_width] = v;
							 | 
						|
								        }
							 | 
						|
								    }
							 | 
						|
								}
							 | 
						|
								
							 | 
						|
								
							 | 
						|
								void CIMAGE::SetPixelsFromNormalizedFloat( const float * aNormalizedFloatArray )
							 | 
						|
								{
							 | 
						|
								    for( unsigned int i = 0; i < m_wxh; i++ )
							 | 
						|
								    {
							 | 
						|
								        int v = aNormalizedFloatArray[i] * 255;
							 | 
						|
								        CLAMP(v, 0, 255);
							 | 
						|
								        m_pixels[i] = v;
							 | 
						|
								    }
							 | 
						|
								}
							 | 
						|
								
							 | 
						|
								
							 | 
						|
								void CIMAGE::SaveAsPNG( wxString aFileName ) const
							 | 
						|
								{
							 | 
						|
								    unsigned char* pixelbuffer = (unsigned char*) malloc( m_wxh * 3 );
							 | 
						|
								
							 | 
						|
								    wxImage image( m_width, m_height );
							 | 
						|
								
							 | 
						|
								    for( unsigned int i = 0; i < m_wxh; i++)
							 | 
						|
								    {
							 | 
						|
								        unsigned char v = m_pixels[i];
							 | 
						|
								        // Set RGB value with all same values intensities
							 | 
						|
								        pixelbuffer[i * 3 + 0] = v;
							 | 
						|
								        pixelbuffer[i * 3 + 1] = v;
							 | 
						|
								        pixelbuffer[i * 3 + 2] = v;
							 | 
						|
								    }
							 | 
						|
								
							 | 
						|
								    image.SetData( pixelbuffer );
							 | 
						|
								    image = image.Mirror( false );
							 | 
						|
								    image.SaveFile( aFileName + ".png", wxBITMAP_TYPE_PNG );
							 | 
						|
								    image.Destroy();
							 | 
						|
								}
							 |