preprocessing.jl

DataAugmentation/preprocessing.jl is a source file in module DataAugmentation

			
			
			
			
			
			"""
			

			    ToEltype(T)

			

			Converts any `AbstractArrayItem` to an `AbstractArrayItem{N, T}`.

			

			Supports `apply!`.

			

			## Examples

			

			{cell=ToEltype}

			```julia

			using DataAugmentation

			

			tfm = ToEltype(Float32)

			item = ArrayItem(rand(Int, 10))

			apply(tfm, item)

			```

			"""
			

			
			
			struct
			
			 
			

	
			ToEltype
			{
			T
			}
			 
			<:
			 

	
			Transform
			
			 
			end
			

			
			

	
			ToEltype
			(
			
			T
			::
			Type
			)
			 
			=
			 
			
			

	
			ToEltype
			{
			T
			}
			(
			)
			

			

			
			
			

	
			apply
			(
			
			::
			

	
			ToEltype
			{
			T
			}
			,
			 
			
			item
			::
			

	
			AbstractArrayItem
			{
			N
			,
			 
			
			<:
			T
			}
			
			;
			 
			
			randstate
			 
			=
			 
			nothing
			)
			 
			where
			 
			{
			N
			,
			 
			T
			}
			 
			=
			 
			item
			

			
			function
			 
			
			

	
			apply
			(
			
			::
			

	
			ToEltype
			{
			T1
			}
			,
			 
			
			item
			::
			

	
			AbstractArrayItem
			{
			N
			,
			 
			T2
			}
			
			;
			 
			
			randstate
			 
			=
			 
			nothing
			)
			 
			where
			 
			{
			N
			,
			 
			T1
			,
			 
			T2
			}
			
			
    
			
			newdata
			 
			=
			 
			
			map
			(
			
			x
			 
			->
			 
			
			convert
			(
			T1
			,
			 
			x
			)
			,
			 
			

	
			itemdata
			(
			item
			)
			)
			
    
			
			item
			 
			=
			 
			

	
			setdata
			(
			item
			,
			 
			newdata
			)
			
    
			
			return
			 
			item
			

			end
			

			

			
			function
			 
			

	
			apply!
			(
			buf
			,
			 
			
			::

	
			ToEltype
			,
			 
			
			item
			::

	
			AbstractArrayItem
			
			;
			 
			
			randstate
			 
			=
			 
			nothing
			)
			
			
    
			## copy! does type conversion under the hood
			
    
			
			copy!
			(
			

	
			itemdata
			(
			buf
			)
			,
			 
			

	
			itemdata
			(
			item
			)
			)
			
    
			
			return
			 
			buf
			

			end

			
			
			
			
			
			"""
			

			    Normalize(means, stds)

			

			Normalizes the last dimension of an `AbstractArrayItem{N}`.

			

			Supports `apply!`.

			

			## Examples

			

			Preprocessing a 3D image with 3 color channels.

			

			{cell=Normalize}

			```julia

			using DataAugmentation, Images

			image = Image(rand(RGB, 20, 20, 20))

			tfms = ImageToTensor() |> Normalize((0.1, -0.2, -0.1), (1,1,1.))

			apply(tfms, image)

			```

			

			"""
			

			
			
			struct
			
			 
			

	
			Normalize
			{
			N
			}
			 
			<:
			 

	
			Transform
			
			
    
			
			means
			::
			
			SVector
			{
			N
			}
			
    
			
			stds
			::
			
			SVector
			{
			N
			}
			

			end
			

			

			
			function
			 
			

	
			Normalize
			(
			means
			,
			 
			stds
			)
			
			
    
			
			
			
			length
			(
			means
			)
			 
			==
			 
			
			length
			(
			stds
			)
			 
			||
			 
			
			error
			(
			
			"
			`means` and `stds` must have same length
			"
			)
			
    
			
			N
			 
			=
			 
			
			length
			(
			means
			)
			
    
			
			return
			 
			
			

	
			Normalize
			{
			N
			}
			(
			
			
			SVector
			{
			N
			}
			(
			means
			)
			,
			 
			
			
			SVector
			{
			N
			}
			(
			stds
			)
			)
			

			end
			

			

			
			function
			 
			
			

	
			apply
			(
			
			tfm
			::

	
			Normalize
			,
			 
			
			item
			::
			

	
			ArrayItem
			{
			N
			,
			 
			T
			}
			
			;
			 
			
			randstate
			 
			=
			 
			nothing
			)
			 
			where
			 
			{
			N
			,
			 
			T
			}
			
			
    
			
			return
			 
			

	
			ArrayItem
			(
			

	
			normalize
			(
			

	
			itemdata
			(
			item
			)
			,
			 
			
			tfm
			.
			
			means
			,
			 
			
			tfm
			.
			
			stds
			)
			)
			

			end
			

			

			
			function
			 
			

	
			apply!
			(
			
        
			buf
			,
			
        
			
			tfm
			::

	
			Normalize
			,
			
        
			
			item
			::

	
			ArrayItem
			
			;
			
        
			
			randstate
			 
			=
			 
			nothing
			)
			
			
    
			
			copy!
			(
			

	
			itemdata
			(
			buf
			)
			,
			 
			

	
			itemdata
			(
			item
			)
			)
			
    
			

	
			normalize!
			(
			

	
			itemdata
			(
			buf
			)
			,
			 
			
			tfm
			.
			
			means
			,
			 
			
			tfm
			.
			
			stds
			)
			
    
			
			return
			 
			buf
			

			end
			

			

			

			
			function
			 
			
			

	
			normalize!
			(
			
        
			
			a
			::
			
			AbstractArray
			{
			T
			,
			 
			N
			}
			,
			
        
			
			means
			::
			
			SVector
			{
			M
			}
			,
			
        
			
			stds
			::
			
			SVector
			{
			M
			}
			)
			 
			where
			 
			{
			N
			,
			 
			T
			,
			 
			M
			}
			
			
    
			
			means
			 
			=
			 
			
			reshape
			(
			
			convert
			.
			
			(
			T
			,
			 
			means
			)
			,
			 
			
			(
			
			1
			 
			for
			
			 
			_
			 
			=
			
			 
			2
			:
			N
			)
			...
			,
			 
			M
			)
			
    
			
			stds
			 
			=
			 
			
			reshape
			(
			
			convert
			.
			
			(
			T
			,
			 
			stds
			)
			,
			 
			
			(
			
			1
			 
			for
			
			 
			_
			 
			=
			
			 
			2
			:
			N
			)
			...
			,
			 
			M
			)
			
    
			
			a
			 
			.-=
			 
			means
			
    
			
			a
			 
			./=
			 
			stds
			
    
			
			return
			 
			a
			

			end
			

			

			
			

	
			normalize
			(
			a
			,
			 
			means
			,
			 
			stds
			)
			 
			=
			 
			

	
			normalize!
			(
			
			copy
			(
			a
			)
			,
			 
			means
			,
			 
			stds
			)
			

			

			
			function
			 
			
			

	
			denormalize!
			(
			
        
			
			a
			::
			
			AbstractArray
			{
			T
			,
			 
			N
			}
			,
			
        
			
			means
			::
			
			SVector
			{
			M
			}
			,
			
        
			
			stds
			::
			
			SVector
			{
			M
			}
			)
			 
			where
			 
			{
			N
			,
			 
			T
			,
			 
			M
			}
			
			
    
			
			means
			 
			=
			 
			
			reshape
			(
			
			convert
			.
			
			(
			T
			,
			 
			means
			)
			,
			 
			
			(
			
			1
			 
			for
			
			 
			_
			 
			=
			
			 
			2
			:
			N
			)
			...
			,
			 
			M
			)
			
    
			
			stds
			 
			=
			 
			
			reshape
			(
			
			convert
			.
			
			(
			T
			,
			 
			stds
			)
			,
			 
			
			(
			
			1
			 
			for
			
			 
			_
			 
			=
			
			 
			2
			:
			N
			)
			...
			,
			 
			M
			)
			
    
			
			a
			 
			.*=
			 
			stds
			
    
			
			a
			 
			.+=
			 
			means
			
    
			
			return
			 
			a
			

			end
			

			

			
			

	
			denormalize
			(
			a
			,
			 
			means
			,
			 
			stds
			)
			 
			=
			 
			

	
			denormalize!
			(
			
			copy
			(
			a
			)
			,
			 
			means
			,
			 
			stds
			)

[ NormalizeIntensity]


			
			
			
			"""
			

			    NormalizeIntensity()

			

			Normalizes the pixels of an array based on calculated mean and std.

			"""
			

			

			
			
			struct
			
			 

	
			NormalizeIntensity
			 
			<:
			 

	
			Transform
			
			 
			end
			

			

			
			function
			 
			

	
			apply
			(
			
			tfm
			::

	
			NormalizeIntensity
			,
			 
			
			item
			::

	
			ArrayItem
			
			;
			 
			
			randstate
			 
			=
			 
			nothing
			)
			
			
    
			
			array
			 
			=
			 
			

	
			itemdata
			(
			item
			)
			
    
			
			slices
			 
			=
			 
			
			ones
			(
			Bool
			,
			 
			
			size
			(
			array
			)
			)
			
    
			
			means
			 
			=
			 
			
			mean
			(
			
			array
			[
			slices
			]
			)
			
    
			
			stds
			 
			=
			 
			
			std
			(
			
			array
			[
			slices
			]
			)
			
    
			
			
			array
			[
			slices
			]
			 
			=
			
			 
			(
			
			
			array
			[
			slices
			]
			 
			.-
			 
			means
			)
			 
			/
			 
			stds
			
    
			
			return
			 
			

	
			ArrayItem
			(
			array
			)
			

			end

[ ImageToTensor]


			
			
			
			
			
			"""
			

			    ImageToTensor()

			

			Expands an `Image{N, T}` of size `sz` to an `ArrayItem{N+1}` with

			size `(sz..., ch)` where `ch` is the number of color channels of `T`.

			

			Supports `apply!`.

			

			## Examples

			

			{cell=ImageToTensor}

			```julia

			using DataAugmentation, Images

			

			image = Image(rand(RGB, 50, 50))

			tfm = ImageToTensor()

			apply(tfm, image)

			```

			

			"""
			

			
			
			struct
			
			 
			

	
			ImageToTensor
			{
			T
			}
			 
			<:
			 

	
			Transform
			
			 
			end
			

			

			
			

	
			ImageToTensor
			(
			
			
			T
			::
			
			Type
			{
			
			<:
			Number
			}
			 
			=
			 
			Float32
			)
			 
			=
			 
			
			

	
			ImageToTensor
			{
			T
			}
			(
			)
			

			

			

			
			function
			 
			
			

	
			apply
			(
			
			::
			

	
			ImageToTensor
			{
			T
			}
			,
			 
			
			image
			::

	
			Image
			
			;
			 
			
			randstate
			 
			=
			 
			nothing
			)
			 
			where
			 
			T
			
			
    
			
			return
			 
			

	
			ArrayItem
			(
			

	
			imagetotensor
			(
			

	
			itemdata
			(
			image
			)
			,
			 
			T
			)
			)
			

			end
			

			

			

			
			function
			 
			

	
			apply!
			(
			buf
			,
			 
			
			::

	
			ImageToTensor
			,
			 
			
			image
			::

	
			Image
			
			;
			 
			
			randstate
			 
			=
			 
			nothing
			)
			
			
    
			

	
			imagetotensor!
			(
			
			buf
			.
			
			data
			,
			 
			
			image
			.
			
			data
			)
			
    
			
			return
			 
			buf
			

			end
			

			

			
			function
			 
			
			

	
			imagetotensor
			(
			
			image
			::
			
			AbstractArray
			{
			C
			,
			 
			N
			}
			,
			 
			
			T
			 
			=
			 
			Float32
			)
			 
			where
			 
			{
			
			C
			<:
			Color
			,
			 
			N
			}
			
			
    
			
			T
			.
			
			(
			
			PermutedDimsArray
			(
			
			_channelview
			(
			image
			)
			,
			 
			
			(
			
			(
			
			i
			 
			for
			
			 
			i
			 
			in
			
			 
			2
			:
			
			N
			+
			1
			)
			...
			,
			 
			1
			)
			)
			)
			

			end

function imagetotensor(image::AbstractArray, T = Float32) where {TC, C<:Color{TC, 1}, N} return T.(_channelview(image)) end TODO: relax color type constraint, implement for other colors single-channel colors need a channelview that also expands the array


			
			
			
			function
			 
			
			

	
			imagetotensor!
			(
			buf
			,
			 
			
			image
			::
			
			AbstractArray
			{
			
			<:
			Color
			,
			 
			N
			}
			)
			 
			where
			 
			N
			
			
    
			
			permutedims!
			(
			
        
			buf
			,
			
        
			
			_channelview
			(
			image
			)
			,
			
        
			
			(
			
			
			2
			:
			
			N
			+
			1
			...
			,
			 
			1
			)
			)
			

			end
			

			

			
			function
			 
			

	
			tensortoimage
			(
			
			a
			::
			AbstractArray
			)
			
			
    
			
			nchannels
			 
			=
			 
			
			
			size
			(
			a
			)
			[
			end
			]
			
    
			
			if
			
			 
			nchannels
			 
			==
			 
			3
			
			
        
			
			return
			 
			

	
			tensortoimage
			(
			RGB
			,
			 
			a
			)
			
    
			
			elseif
			
			 
			nchannels
			 
			==
			 
			1
			
			
        
			
			return
			 
			

	
			tensortoimage
			(
			Gray
			,
			 
			a
			)
			
    
			else
			
			
        
			
			error
			(
			
			"
			Found image tensor with 
			$
			nchannels
			 color channels. Pass in color type
                explicitly.
			"
			)
			
    
			end
			

			end
			

			

			
			function
			 
			
			

	
			tensortoimage
			(
			
			C
			::
			
			Type
			{
			
			<:
			Color
			}
			,
			 
			
			a
			::
			
			AbstractArray
			{
			T
			,
			 
			N
			}
			)
			 
			where
			 
			{
			T
			,
			 
			N
			}
			
			
    
			
			perm
			 
			=
			 
			
			(
			N
			,
			 
			
			
			1
			:
			
			N
			-
			1
			...
			)
			
    
			
			return
			 
			
			_colorview
			(
			C
			,
			 
			
			PermutedDimsArray
			(
			a
			,
			 
			perm
			)
			)
			

			end
			

			

			

			
			function
			 
			
			_channelview
			(
			img
			)
			
			
    
			
			chview
			 
			=
			 
			
			channelview
			(
			img
			)
			
    
			# for single-channel colors, expand the color dimension anyway
			
    
			
			if
			
			 
			
			size
			(
			img
			)
			 
			==
			 
			
			size
			(
			chview
			)
			
			
        
			
			chview
			 
			=
			 
			
			reshape
			(
			chview
			,
			 
			1
			,
			 
			
			
			size
			(
			chview
			)
			...
			)
			
    
			end
			
    
			
			return
			 
			chview
			

			end
			

			

			
			function
			 
			
			_colorview
			(
			
			C
			::
			
			Type
			{
			
			<:
			Color
			}
			,
			 
			img
			)
			
			
    
			
			if
			
			 
			
			size
			(
			img
			,
			 
			1
			)
			 
			==
			 
			1
			
			
        
			
			img
			 
			=
			 
			
			reshape
			(
			img
			,
			 
			
			
			size
			(
			img
			)
			[
			
			2
			:
			end
			]
			)
			
    
			end
			
    
			
			return
			 
			
			colorview
			(
			C
			,
			 
			img
			)
			

			end

OneHot encoding


			
			
			
			
			
			"""
			

			    OneHot([T = Float32])

			

			One-hot encodes a `MaskMulti` with `n` classes and size `sz` into

			an array item of size `(sz..., n)` with element type `T`. Supports [`apply!`](#).

			

			```julia

			item = MaskMulti(rand(1:4, 100, 100), 1:4)

			apply(OneHot(), item)

			```

			"""
			

			
			
			struct
			
			 
			

	
			OneHot
			{
			T
			}
			 
			<:
			 

	
			Transform
			
			 
			end
			

			
			

	
			OneHot
			(
			)
			 
			=
			 
			
			

	
			OneHot
			{
			Float32
			}
			(
			)
			

			

			
			function
			 
			
			

	
			apply
			(
			
			tfm
			::
			

	
			OneHot
			{
			T
			}
			,
			 
			
			item
			::

	
			MaskMulti
			
			;
			 
			
			randstate
			 
			=
			 
			nothing
			)
			 
			where
			 
			T
			
			
    
			
			mask
			 
			=
			 
			
			parent
			(
			

	
			itemdata
			(
			item
			)
			)
			
    
			
			a
			 
			=
			 
			
			zeros
			(
			T
			,
			 
			
			
			size
			(
			mask
			)
			...
			,
			 
			
			length
			(
			
			item
			.
			
			classes
			)
			)
			
    
			
			for
			
			 
			I
			 
			in
			 
			
			CartesianIndices
			(
			mask
			)
			
			
        
			
			
			a
			[
			I
			,
			 
			
			mask
			[
			I
			]
			]
			 
			=
			 
			
			one
			(
			T
			)
			
    
			end
			

			
    
			
			return
			 
			

	
			ArrayItem
			(
			a
			)
			

			end
			

			

			

			
			function
			 
			
			

	
			apply!
			(
			buf
			,
			 
			
			tfm
			::
			

	
			OneHot
			{
			T
			}
			,
			 
			
			item
			::

	
			MaskMulti
			
			;
			 
			
			randstate
			 
			=
			 
			nothing
			)
			 
			where
			 
			T
			
			
    
			
			mask
			 
			=
			 
			
			parent
			(
			

	
			itemdata
			(
			item
			)
			)
			
    
			
			a
			 
			=
			 
			

	
			itemdata
			(
			buf
			)
			
    
			
			fill!
			(
			a
			,
			 
			
			zero
			(
			T
			)
			)
			

			
    
			
			for
			
			 
			I
			 
			in
			 
			
			CartesianIndices
			(
			mask
			)
			
			
        
			
			
			a
			[
			I
			,
			 
			
			mask
			[
			I
			]
			]
			 
			=
			 
			
			one
			(
			T
			)
			
    
			end
			

			
    
			
			return
			 
			buf
			

			end
			

			

			

			
			function
			 
			

	
			onehot
			(
			T
			,
			 
			
			x
			::
			Int
			,
			 
			
			n
			::
			Int
			)
			
			
    
			
			v
			 
			=
			 
			
			fill
			(
			
			zero
			(
			T
			)
			,
			 
			n
			)
			
    
			
			
			v
			[
			x
			]
			 
			=
			 
			
			one
			(
			T
			)
			
    
			
			return
			 
			v
			

			end
			

			
			

	
			onehot
			(
			x
			,
			 
			n
			)
			 
			=
			 
			

	
			onehot
			(
			Float32
			,
			 
			x
			,
			 
			n
			)