Skip to content

Repository files navigation

Swift Image Processing

This project contains swift playgrounds that demonstrate how to do pixel operations in swift.

  • Swift4 : checkout master branch
  • Swift3.x : checkout syntax/swift3.x branch
  • Swift2.x : checkout syntax/swift2.x branch

Thanks to RGBAImage

Convert UIImage to RGBA Image

RGBAImage has pixels flat memory. You can access pixels with index directly.

Contrast

This is example for pixel operation

letrgba=RGBAImage(image:UIImage(named:"monet")!)!
vartotalR=0vartotalG=0vartotalB=0
rgba.process{(pixel)->Pixelin
totalR +=Int(pixel.R)
totalG +=Int(pixel.G)
totalB +=Int(pixel.B)return pixel
}letpixelCount= rgba.width * rgba.height
letavgR= totalR / pixelCount
letavgG= totalG / pixelCount
letavgB= totalB / pixelCount
func contrast(_ image:RGBAImage)->RGBAImage{
image.process{(pixel)->Pixelinvarpixel= pixel
letdeltaR=Int(pixel.R)- avgR
letdeltaG=Int(pixel.G)- avgG
letdeltaB=Int(pixel.B)- avgB
pixel.R =UInt8(max(min(255, avgR +3* deltaR),0)) //clamp
pixel.G =UInt8(max(min(255, avgG +3* deltaG),0))
pixel.B =UInt8(max(min(255, avgB +3* deltaB),0))return pixel
}return image
}letnewImage=contrast(rgba).toUIImage()

Grab color space

Grab Red component

func grabR(_ image:RGBAImage)->RGBAImage{varoutImage= image
outImage.process{(pixel)->Pixelinvarpixel= pixel
pixel.R = pixel.R
pixel.G =0
pixel.B =0return pixel
}return outImage
}

Grab Green component

func grabG(_ image:RGBAImage)->RGBAImage{varoutImage= image
outImage.process{(pixel)->Pixelinvarpixel= pixel
pixel.R =0
pixel.G = pixel.G
pixel.B =0return pixel
}return outImage
}

Grab Blue component

func grabB(_ image:RGBAImage)->RGBAImage{varoutImage= image
outImage.process{(pixel)->Pixelinvarpixel= pixel
pixel.R =0
pixel.G =0
pixel.B = pixel.B
return pixel
}return outImage
}

Compose RGB Color components

public static func composite(_ rgbaImageList: RGBAImage...) -> RGBAImage {
let result : RGBAImage = RGBAImage(width:rgbaImageList[0].width, height: rgbaImageList[0].height)
for y in 0..<result.height {
for x in 0..<result.width {
let index = y * result.width + x
var pixel = result.pixels[index]
for rgba in rgbaImageList {
let rgbaPixel = rgba.pixels[index]
pixel.Rf = pixel.Rf + rgbaPixel.Rf
pixel.Gf = pixel.Gf + rgbaPixel.Gf
pixel.Bf = pixel.Bf + rgbaPixel.Bf
}
result.pixels[index] = pixel
}
}
return result
}

RGB to Gray

publicstaticfunc gray5(_ image:RGBAImage)->RGBAImage{varoutImage= image
outImage.process{(pixel)->Pixelinvarpixel= pixel
letresult=sqrt(pow(pixel.Rf,2)+ pow(pixel.Rf,2)+ pow(pixel.Rf,2))/sqrt(3.0)
pixel.Rf = result
pixel.Gf = result
pixel.Bf = result
return pixel
}return outImage
}letrgba5=RGBAImage(image:UIImage(named:"monet")!)!
gray5(rgba5).toUIImage()

Refactoring Split Color Space

publicstaticfunc splitRGB(_ rgba:RGBAImage)->(ByteImage,ByteImage,ByteImage){letR=ByteImage(width: rgba.width, height: rgba.height)letG=ByteImage(width: rgba.width, height: rgba.height)letB=ByteImage(width: rgba.width, height: rgba.height)
rgba.enumerate{(index, pixel)->VoidinR.pixels[index]= pixel.R.toBytePixel()G.pixels[index]= pixel.G.toBytePixel()B.pixels[index]= pixel.B.toBytePixel()}return(R, G, B)}

ByteImage has only one color component.

Images ADD, SUB, MUL, DIV

publicstaticfunc op(_ functor :(Double,Double)->Double, rgbaImage1:RGBAImage, rgbaImage2:RGBAImage)->RGBAImage{letresult:RGBAImage=RGBAImage(width:rgbaImage1.width, height: rgbaImage1.height)foryin0..<result.height {forxin0..<result.width {letindex= y * result.width + x
varpixel= result.pixels[index]letrgba1Pixel= rgbaImage1.pixels[index]letrgba2Pixel= rgbaImage2.pixels[index]
pixel.Rf =functor(rgba1Pixel.Rf, rgba2Pixel.Rf)
pixel.Gf =functor(rgba1Pixel.Gf, rgba2Pixel.Gf)
pixel.Bf =functor(rgba1Pixel.Bf, rgba2Pixel.Bf)
result.pixels[index]= pixel
}}return result }publicstaticfunc add(rgba1:RGBAImage, _ rgba2:RGBAImage)->RGBAImage{returnop((+), rgbaImage1: rgba1, rgbaImage2: rgba2)}

Blending

publicstaticfunc blending(_ img1:RGBAImage, _ img2:RGBAImage, alpha:Double)->RGBAImage{letresult:RGBAImage=RGBAImage(width:img1.width, height: img1.height)foryin0..<result.height {forxin0..<result.width {letindex= y * result.width + x
varpixel= result.pixels[index]letpixel1= img1.pixels[index]letpixel2= img2.pixels[index]
pixel.Rf = alpha * pixel1.Rf +(1.0- alpha)* pixel2.Rf
pixel.Gf = alpha * pixel1.Gf +(1.0- alpha)* pixel2.Gf
pixel.Bf = alpha * pixel1.Bf +(1.0- alpha)* pixel2.Bf
result.pixels[index]= pixel
}}return result
}

Brightness

publicstaticfunc brightness(_ img1:RGBAImage, contrast:Double, brightness:Double)->RGBAImage{letresult:RGBAImage=RGBAImage(width:img1.width, height: img1.height)foryin0..<result.height {forxin0..<result.width {letindex= y * result.width + x
varpixel= result.pixels[index]letpixel1= img1.pixels[index]
pixel.Rf = pixel1.Rf * contrast + brightness
pixel.Gf = pixel1.Gf * contrast + brightness
pixel.Bf = pixel1.Bf * contrast + brightness
result.pixels[index]= pixel
}}return result
}

Convolution

publicstaticfunc convolution(_ image:ByteImage, mask:Array2D<Double>)->ByteImage{varimage= image
letheight= image.height
letwidth= image.width
letmaskHeight= mask.rowCount()letmaskWidth= mask.colCount()foryin0..<height - maskHeight +(maskHeight-1)/2{forxin0..<width - maskWidth +(maskWidth-1)/2{varv=0.0if(y+maskHeight > height) || (x+maskWidth)> width {continue}formyin0..<maskHeight {formxin0..<maskWidth {lettmp=mask[my, mx]
v = v +(image.pixel(x+mx, y+my)!.Cf * tmp)}}
v =clamp(v, lower:0.0, upper:1.0)print(v)letpixel=BytePixel(value: v)letxx= x+(maskWidth-1)/2letyy= y+(maskHeight-1)/2
image.setPixel(xx, yy, pixel)}}return image
}

Sharpening

letm1=Array2D(cols:3, rows:3,[0.0/5.0,-1.0/5.0,0.0/5.0,-1.0/5.0,9.0/5.0,-1.0/5.0,0.0/5.0,-1.0/5.0,0.0/5.0])ImageProcess.convolution(R.clone(), mask: m1).toUIImage()

Bluring

letm2=Array2D(cols:3, rows:3,[1.0/9.0,1.0/9.0,1.0/9.0,1.0/9.0,1.0/9.0,1.0/9.0,1.0/9.0,1.0/9.0,1.0/9.0,])ImageProcess.convolution(R.clone(), mask: m2).toUIImage()

MIT License

The MIT License

Copyright © 2015 Sungcheol Kim, https://github.com/skyfe79/SwiftImageProcessing

Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

About

This project demonstrates how to do pixel operations in swift.

Resources

Stars

528 stars

Watchers

13 watching

Forks

Releases

Packages

Contributors

Languages