{"id":18269694,"url":"https://github.com/skyfe79/swiftimageprocessing","last_synced_at":"2025-04-05T20:07:57.962Z","repository":{"id":41380797,"uuid":"53959299","full_name":"skyfe79/SwiftImageProcessing","owner":"skyfe79","description":"This project demonstrates how to do pixel operations in swift.","archived":false,"fork":false,"pushed_at":"2019-07-29T14:26:39.000Z","size":1193,"stargazers_count":527,"open_issues_count":0,"forks_count":36,"subscribers_count":16,"default_branch":"master","last_synced_at":"2025-03-29T19:06:18.402Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Swift","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/skyfe79.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2016-03-15T16:09:28.000Z","updated_at":"2025-02-27T05:21:09.000Z","dependencies_parsed_at":"2022-09-12T04:01:30.116Z","dependency_job_id":null,"html_url":"https://github.com/skyfe79/SwiftImageProcessing","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/skyfe79%2FSwiftImageProcessing","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/skyfe79%2FSwiftImageProcessing/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/skyfe79%2FSwiftImageProcessing/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/skyfe79%2FSwiftImageProcessing/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/skyfe79","download_url":"https://codeload.github.com/skyfe79/SwiftImageProcessing/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247393570,"owners_count":20931812,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-11-05T11:36:52.671Z","updated_at":"2025-04-05T20:07:57.941Z","avatar_url":"https://github.com/skyfe79.png","language":"Swift","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Swift Image Processing\n\nThis project contains swift playgrounds that demonstrate how to do pixel operations in swift.\n\n * Swift4 : checkout master branch\n * Swift3.x : checkout syntax/swift3.x branch\n * Swift2.x : checkout syntax/swift2.x branch\n\n## Thanks to RGBAImage\n\n* [http://mhorga.org/2015/10/19/image-processing-in-ios-part-3.html](http://mhorga.org/2015/10/19/image-processing-in-ios-part-3.html)\n* This articles help me a lot!\n\n## Convert UIImage to RGBA Image\nRGBAImage has pixels flat memory. You can access pixels with index directly.\n\n![](art/01_rgba_image.png)\n\n## Contrast \nThis is example for pixel operation\n\n![](art/02_contrast.png)\n\n```swift\nlet rgba = RGBAImage(image: UIImage(named: \"monet\")!)!\n\n\nvar totalR = 0\nvar totalG = 0\nvar totalB = 0\n\nrgba.process { (pixel) -\u003e Pixel in\n    totalR += Int(pixel.R)\n    totalG += Int(pixel.G)\n    totalB += Int(pixel.B)\n    return pixel\n}\n\nlet pixelCount = rgba.width * rgba.height\nlet avgR = totalR / pixelCount\nlet avgG = totalG / pixelCount\nlet avgB = totalB / pixelCount\n\n\n\nfunc contrast(_ image: RGBAImage) -\u003e RGBAImage {\n    \n    image.process { (pixel) -\u003e Pixel in\n        var pixel = pixel\n        let deltaR = Int(pixel.R) - avgR\n        let deltaG = Int(pixel.G) - avgG\n        let deltaB = Int(pixel.B) - avgB\n        pixel.R = UInt8(max(min(255, avgR + 3 * deltaR), 0)) //clamp\n        pixel.G = UInt8(max(min(255, avgG + 3 * deltaG), 0))\n        pixel.B = UInt8(max(min(255, avgB + 3 * deltaB), 0))\n        \n        return pixel\n    }\n    return image\n}\n\nlet newImage = contrast(rgba).toUIImage()\n```\n## Grab color space\n\n### Grab Red component\n![](art/03_grab_r.png)\n\n```swift\nfunc grabR(_ image: RGBAImage) -\u003e RGBAImage {\n    var outImage = image\n    outImage.process { (pixel) -\u003e Pixel in\n        var pixel = pixel\n        pixel.R = pixel.R\n        pixel.G = 0\n        pixel.B = 0\n        return pixel\n    }\n    return outImage\n}\n```\n\n### Grab Green component\n\n![](art/04_grab_g.png)\n\n```swift\nfunc grabG(_ image: RGBAImage) -\u003e RGBAImage {\n    var outImage = image\n    outImage.process { (pixel) -\u003e Pixel in\n        var pixel = pixel\n        pixel.R = 0\n        pixel.G = pixel.G\n        pixel.B = 0\n        return pixel\n    }\n    return outImage\n}\n```\n### Grab Blue component\n\n![](art/05_grab_b.png)\n\n```swift\nfunc grabB(_ image: RGBAImage) -\u003e RGBAImage {\n    var outImage = image\n    outImage.process { (pixel) -\u003e Pixel in\n        var pixel = pixel\n        pixel.R = 0\n        pixel.G = 0\n        pixel.B = pixel.B\n        return pixel\n    }\n    return outImage\n}\n```\n### Compose RGB Color components\n\n![](art/06_composite.png)\n\n```\npublic static func composite(_ rgbaImageList: RGBAImage...) -\u003e RGBAImage {\n        let result : RGBAImage = RGBAImage(width:rgbaImageList[0].width, height: rgbaImageList[0].height)\n        for y in 0..\u003cresult.height {\n            for x in 0..\u003cresult.width {\n                \n                let index = y * result.width + x\n                var pixel = result.pixels[index]\n                \n                for rgba in rgbaImageList {\n                    let rgbaPixel = rgba.pixels[index]\n                    pixel.Rf = pixel.Rf + rgbaPixel.Rf\n                    pixel.Gf = pixel.Gf + rgbaPixel.Gf\n                    pixel.Bf = pixel.Bf + rgbaPixel.Bf\n                }\n                \n                result.pixels[index] = pixel\n            }\n        }\n        return result\n    }\n```\n\n## RGB to Gray\n![](art/07_rgb_to_gray.png)\n\n```swift\npublic static func gray5(_ image: RGBAImage) -\u003e RGBAImage {\n        var outImage = image\n        outImage.process { (pixel) -\u003e Pixel in\n            var pixel = pixel\n            let result = sqrt(pow(pixel.Rf, 2) + pow(pixel.Rf, 2) + pow(pixel.Rf, 2))/sqrt(3.0)\n            pixel.Rf = result\n            pixel.Gf = result\n            pixel.Bf = result\n            return pixel\n        }\n        return outImage\n}\nlet rgba5 = RGBAImage(image: UIImage(named: \"monet\")!)!\ngray5(rgba5).toUIImage()\n```\n\n## Refactoring Split Color Space\n![](art/08_split.png)\n\n```swift\npublic static func splitRGB(_ rgba: RGBAImage) -\u003e (ByteImage, ByteImage, ByteImage) {\n    let R = ByteImage(width: rgba.width, height: rgba.height)\n    let G = ByteImage(width: rgba.width, height: rgba.height)\n    let B = ByteImage(width: rgba.width, height: rgba.height)\n    \n    rgba.enumerate { (index, pixel) -\u003e Void in\n        \n        R.pixels[index] = pixel.R.toBytePixel()\n        G.pixels[index] = pixel.G.toBytePixel()\n        B.pixels[index] = pixel.B.toBytePixel()\n    }\n    \n    return (R, G, B)\n}\n```\n`ByteImage` has only one color component. \n\n## Images ADD, SUB, MUL, DIV\n![](art/09_add_sub_mul_div.png)\n\n```swift\npublic static func op(_ functor : (Double, Double) -\u003e Double, rgbaImage1: RGBAImage, rgbaImage2: RGBAImage) -\u003e RGBAImage {\n    let result : RGBAImage = RGBAImage(width:rgbaImage1.width, height: rgbaImage1.height)\n    for y in 0..\u003cresult.height {\n        for x in 0..\u003cresult.width {\n            \n            let index = y * result.width + x\n            var pixel = result.pixels[index]\n            \n            let rgba1Pixel = rgbaImage1.pixels[index]\n            let rgba2Pixel = rgbaImage2.pixels[index]\n            \n            \n            pixel.Rf = functor(rgba1Pixel.Rf, rgba2Pixel.Rf)\n            pixel.Gf = functor(rgba1Pixel.Gf, rgba2Pixel.Gf)\n            pixel.Bf = functor(rgba1Pixel.Bf, rgba2Pixel.Bf)\n            \n            result.pixels[index] = pixel\n        }\n    }\n    return result   \n}\n\npublic static func add(rgba1: RGBAImage, _ rgba2: RGBAImage) -\u003e RGBAImage {\n    return op((+), rgbaImage1: rgba1, rgbaImage2: rgba2)\n}\n```\n\n![](art/10_add_sub_mul_div.png)\n\n## Blending\n![](art/11_blending.png)\n\n```swift\npublic static func blending(_ img1: RGBAImage, _ img2: RGBAImage, alpha: Double) -\u003e RGBAImage {\n    let result : RGBAImage = RGBAImage(width:img1.width, height: img1.height)\n    for y in 0..\u003cresult.height {\n        for x in 0..\u003cresult.width {\n            \n            let index = y * result.width + x\n            var pixel = result.pixels[index]\n            \n            let pixel1 = img1.pixels[index]\n            let pixel2 = img2.pixels[index]\n            \n            \n            pixel.Rf = alpha * pixel1.Rf + (1.0 - alpha) * pixel2.Rf\n            pixel.Gf = alpha * pixel1.Gf + (1.0 - alpha) * pixel2.Gf\n            pixel.Bf = alpha * pixel1.Bf + (1.0 - alpha) * pixel2.Bf\n            \n            result.pixels[index] = pixel\n        }\n    }\n    return result\n}\n```\n\n## Brightness\n![](art/12_brightness.png)\n\n```swift\npublic static func brightness(_ img1: RGBAImage, contrast: Double, brightness: Double) -\u003e RGBAImage {\n    let result : RGBAImage = RGBAImage(width:img1.width, height: img1.height)\n    for y in 0..\u003cresult.height {\n        for x in 0..\u003cresult.width {\n            \n            let index = y * result.width + x\n            var pixel = result.pixels[index]\n            \n            let pixel1 = img1.pixels[index]\n            \n            pixel.Rf = pixel1.Rf * contrast + brightness\n            pixel.Gf = pixel1.Gf * contrast + brightness\n            pixel.Bf = pixel1.Bf * contrast + brightness\n            \n            result.pixels[index] = pixel\n        }\n    }\n    return result\n}\n```\n\n## Convolution\n\n```swift\npublic static func convolution(_ image: ByteImage, mask: Array2D\u003cDouble\u003e) -\u003e ByteImage {\n    var image = image\n    let height = image.height\n    let width  = image.width\n    \n    let maskHeight = mask.rowCount()\n    let maskWidth  = mask.colCount()\n    \n    for y in 0..\u003cheight - maskHeight + (maskHeight-1)/2 {\n        for x in 0..\u003cwidth - maskWidth + (maskWidth-1)/2 {\n            var v = 0.0\n            if (y+maskHeight \u003e height) || (x+maskWidth) \u003e width {\n                continue\n            }\n            \n            for my in 0..\u003cmaskHeight {\n                for mx in 0..\u003cmaskWidth {\n                    let tmp = mask[my, mx]\n                    v = v + (image.pixel(x+mx, y+my)!.Cf * tmp)\n                }\n            }\n            \n            v = clamp(v, lower: 0.0, upper: 1.0)\n            print(v)\n            let pixel = BytePixel(value: v)\n            let xx = x+(maskWidth-1)/2\n            let yy = y+(maskHeight-1)/2\n            image.setPixel(xx, yy, pixel)\n        }\n    }\n    return image\n}\n\n```\n\n### Sharpening\n![](art/13_sharpening.png)\n\n```swift\nlet m1 = Array2D(cols:3, rows:3,\n    [ 0.0/5.0, -1.0/5.0, 0.0/5.0,\n     -1.0/5.0,  9.0/5.0,-1.0/5.0,\n      0.0/5.0, -1.0/5.0, 0.0/5.0])\nImageProcess.convolution(R.clone(), mask: m1).toUIImage()\n```\n\n### Bluring\n![](art/14_blur.png)\n\n```swift\nlet m2 = Array2D(cols: 3, rows: 3,\n    [\n         1.0/9.0, 1.0/9.0, 1.0/9.0,\n         1.0/9.0, 1.0/9.0, 1.0/9.0,\n         1.0/9.0, 1.0/9.0, 1.0/9.0,\n    ]\n)\nImageProcess.convolution(R.clone(), mask: m2).toUIImage()\n```\n\n\n## MIT License\n\nThe MIT License\n\nCopyright © 2015 Sungcheol Kim, https://github.com/skyfe79/SwiftImageProcessing\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in\nall copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\nTHE SOFTWARE.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fskyfe79%2Fswiftimageprocessing","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fskyfe79%2Fswiftimageprocessing","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fskyfe79%2Fswiftimageprocessing/lists"}