//*********************************************************************************************************
//  2013 jakemdrew.com. All rights reserved. 
// This source code is licensed under The GNU General Public License (GPLv3):  
// http://opensource.org/licenses/gpl-3.0.html
//*********************************************************************************************************

//*********************************************************************************************************
//R Image Thinning Library 
//Created By - Jake Drew, Dr. Michael Hahsler 
//Version -    1.0, 04/28/2013
//*********************************************************************************************************

library(seriation)

absDiff <- function(matrix1,matrix2)
{
    r <- nrow(matrix1)
    c <- ncol(matrix1)
    destMatrix <- matrix1
    for(r in 0:r-1)
    {
		for(c in 0:c-1)
		{
			destMatrix[r,c] <- abs(matrix1[r,c]-matrix1[r,c])
		}
    }
    return(destMatrix)
}

countNonZero <- function(inputMatrix)
{
    return(length(inputMatrix[inputMatrix > 0]))
}

thinningIteration <- function(imageMatrix, iter)
{
    imageInput <- imageMatrix
    r <- nrow(imageInput) - 1
    c <- ncol(imageInput) - 1
    for(i in 2:r)
    {
	for(j in 2:c)
	{
	    p2 <- imageInput[i-1, j]
	    p3 <- imageInput[i-1, j+1]
	    p4 <- imageInput[i, j+1]
	    p5 <- imageInput[i+1, j+1]
	    p6 <- imageInput[i+1, j]
	    p7 <- imageInput[i+1, j-1]
	    p8 <- imageInput[i, j-1]
	    p9 <- imageInput[i-1, j-1]
	    A  <- (p2 == 0 && p3 == 1) + (p3 == 0 && p4 == 1) + 
			(p4 == 0 && p5 == 1) + (p5 == 0 && p6 == 1) + 
			(p6 == 0 && p7 == 1) + (p7 == 0 && p8 == 1) +
			(p8 == 0 && p9 == 1) + (p9 == 0 && p2 == 1)
	    B  <- p2 + p3 + p4 + p5 + p6 + p7 + p8 + p9
	    if(iter == 0){
			m1 <- (p2 * p4 * p6)
			m2 <- (p4 * p6 * p8)
	    }
	    else {
			m1 <- (p2 * p4 * p8)
			m2 <- (p2 * p6 * p8)
	    }
	    if (A == 1 && (B >= 2 && B <= 6) && m1 == 0 && m2 == 0)
	    {
			imageInput[i,j] <- 0
	    }
	}
    }
    return(imageInput)
}

thinImage <- function(imageMatrix)
{
    
    im <- imageMatrix
    prev <- im
    repeat {
		im <- thinningIteration(im, 0)
		im <- thinningIteration(im, 1)
		diff <- absDiff(im, prev)
		prev <- im
		if(countNonZero(diff) <= 0)
		{
			break
		}
    } 

    return(im)
}

//*****************************************************************************
//Example Usage Below 
//*****************************************************************************

//reference the seriation library for pimage()
if(!require(seriation)){install.packages("seriation")}
library(seriation)

//read in the images collection and convert it to a matrix
numbers <- read.csv("numbers.csv", header=TRUE)

//define a function for getting a single image matrix
allImagesMatrix <- function(x) matrix(as.numeric(x), nrow=28, byrow=TRUE)

//Get a single image from the collection
singleImageMatrix <- allImagesMatrix(numbers[2,])

//Display the gray scale image
pimage(singleImageMatrix)

//convert the image to a binary image 
singleImageMatrix  <- singleImageMatrix>100

//Display the binary image
pimage(singleImageMatrix)

//Thin the image using our thinning library 
thin <- thinImage(singleImageMatrix)

//Display the thinned image
pimage(thin)