Archive for the 'CIImage' Category

2017/08/22 CIFilterで画像切り抜き

CIFilterで画像の切り抜きを行うAppleScriptです。指定画像と同一階層のフォルダにUUID.pngの切り抜き画像を作成します。

Cocoaでの画像切り抜きは、

NSBitmapImageRepで切り抜き元画像の指定範囲のBitmapを取得して、新規NSBitmapImageRepに描画して結果を取得

というのが常識的なやり方のようですが、CIFilterの機能を用いて切り抜きできることを知ったので、比較のために実行してみました。

crop100images.png

結局、CIFilterの方が20倍ぐらい遅かったので、NSBitmapImageRepを使うやり方で問題ないことがわかりました。NSImageを100回指定範囲で切り抜くのに、NSBitmapImageRepで0.10950499773秒(1回あたり0.001秒)、このCIFilter経由だと1.957534968853秒(1回あたり0.02秒)でした(@MacBook Pro Retina 2012 Core i7 2.66GHz)。

もしかしたら、最近のGPU性能が向上したマシンだとこの差が小さくなるのかもしれません(CPU性能はたいして向上していない一方で、GPU性能は大きく向上しているはずなので)。

AppleScript名:CIFilterで画像切り抜き
– Created 2017-08-22 by Takaaki Naganoya
– 2017 Piyomaru Software
use AppleScript version “2.4″
use scripting additions
use framework “Foundation”
use framework “QuartzCore”
–http://piyocast.com/as/archives/4788

property CIFilter : a reference to current application’s CIFilter
property CIVector : a reference to current application’s CIVector
property CIImage : a reference to current application’s CIImage
property NSString : a reference to current application’s NSString
property NSUUID : a reference to current application’s NSUUID
property NSPNGFileType : a reference to current application’s NSPNGFileType
property NSBitmapImageRep : a reference to current application’s NSBitmapImageRep
property NSImage : a reference to current application’s NSImage
property |NSURL| : a reference to current application’s |NSURL|

–画像を選択
set aPath to POSIX path of (choose file of type {“public.image”})

set aNSImage to NSImage’s alloc()’s initWithContentsOfFile:aPath
set aSize to aNSImage’s |size|()
set aWidth to aSize’s width()
set aHeight to aSize’s height()

–Crop Image by CIFilter
set cropRes to cropNSImageWithCIFilter(aNSImage, 0, (aHeight - 100), 100, 100) of me

–Save as PNG
set fRes to retUUIDfilePath(aPath, “png”) of me
set sRes to saveNSImageAtPathAsPNG(cropRes, fRes) of me

–NSImageをCIImageに変換してCIfilterを実行
on cropNSImageWithCIFilter(aNSImage, x1, y1, xWidth, yHeight)
  set aCIImage to convNSImageToCIimage(aNSImage) of me
  
set aFilter to CIFilter’s filterWithName:“CICrop”
  
set aCIVector to CIVector’s vectorWithX:x1 Y:y1 Z:xWidth W:yHeight
  
  
aFilter’s setDefaults()
  
aFilter’s setValue:aCIImage forKey:“inputImage”
  
aFilter’s setValue:aCIVector forKey:“inputRectangle”
  
  
set filteredImage to (aFilter’s outputImage)
  
set newNSImage to convCIimageToNSImage(filteredImage) of me
  
  
return newNSImage
end cropNSImageWithCIFilter

on convCIimageToNSImage(aCIImage)
  set aRep to NSBitmapImageRep’s alloc()’s initWithCIImage:aCIImage
  
set tmpSize to aRep’s |size|()
  
set newImg to NSImage’s alloc()’s initWithSize:tmpSize
  
newImg’s addRepresentation:aRep
  
return newImg
end convCIimageToNSImage

on convNSImageToCIimage(aNSImage)
  set tiffDat to aNSImage’s TIFFRepresentation()
  
set aRep to NSBitmapImageRep’s imageRepWithData:tiffDat
  
set newImg to CIImage’s alloc()’s initWithBitmapImageRep:aRep
  
return newImg
end convNSImageToCIimage

on retUUIDfilePath(aPath, aEXT)
  set aUUIDstr to (NSUUID’s UUID()’s UUIDString()) as string
  
set aPath to ((NSString’s stringWithString:aPath)’s stringByDeletingLastPathComponent()’s stringByAppendingPathComponent:aUUIDstr)’s stringByAppendingPathExtension:aEXT
  
return aPath
end retUUIDfilePath

–NSImageを指定パスにPNG形式で保存
on saveNSImageAtPathAsPNG(anImage, outPath)
  set imageRep to anImage’s TIFFRepresentation()
  
set aRawimg to NSBitmapImageRep’s imageRepWithData:imageRep
  
set pathString to NSString’s stringWithString:outPath
  
set newPath to pathString’s stringByExpandingTildeInPath()
  
set myNewImageData to (aRawimg’s representationUsingType:(NSPNGFileType) |properties|:(missing value))
  
set aRes to (myNewImageData’s writeToFile:newPath atomically:true) as boolean
  
return aRes –true/false
end saveNSImageAtPathAsPNG

★Click Here to Open This Script 

2017/03/21 CoreImage(CIFilter)で指定画像を2階調ポスタライズ v2

CoreImageのCIFilterを用いて、指定の画像を2階調でポスタライズするAppleScriptです。

CPUImageにも同様のポスタライズ用のフィルタが存在しているのですが、パラメータを指定してもうまく効かなかったので、CIFilterを使ってみました。

6ba2129c-12c5-42bf-b1a6-48dc883a97ec.png
▲実行前

81421d35-72aa-4d9d-9e6b-e2c59f9c9109.png
▲実行後

AppleScript名:CoreImageで指定画像を2階調ポスタライズ v2
– Created 2017-03-21 by Takaaki Naganoya
– 2017 Piyomaru Software
use AppleScript version “2.4″
use scripting additions
use framework “Foundation”
use framework “ASObjCExtras”
use framework “QuartzCore”
–http://piyocast.com/as/archives/4541

–画像を選択
set aPath to POSIX path of (choose file of type {“public.image”})
set aNSImage to current application’s NSImage’s alloc()’s initWithContentsOfFile:aPath

set imgRes to execCIFilterWithNSImage(aNSImage, “CIColorPosterize”) of me

set aDesktopPath to (current application’s NSProcessInfo’s processInfo()’s environment()’s objectForKey:(“HOME”))’s stringByAppendingString:“/Desktop/”
set savePath to aDesktopPath’s stringByAppendingString:((current application’s NSUUID’s UUID()’s UUIDString())’s stringByAppendingString:“.png”)

set fRes to saveNSImageAtPathAsPNG(imgRes, savePath) of me

on convCIimageToNSImage(aCIImage)
  set aRep to current application’s NSBitmapImageRep’s alloc()’s initWithCIImage:aCIImage
  
set tmpSize to aRep’s |size|()
  
set newImg to current application’s NSImage’s alloc()’s initWithSize:tmpSize
  
newImg’s addRepresentation:aRep
  
return newImg
end convCIimageToNSImage

on convNSImageToCIimage(aNSImage)
  set tiffDat to aNSImage’s TIFFRepresentation()
  
set aRep to current application’s NSBitmapImageRep’s imageRepWithData:tiffDat
  
set newImg to current application’s CIImage’s alloc()’s initWithBitmapImageRep:aRep
  
return newImg
end convNSImageToCIimage

–NSImageをCIImageに変換してCIfilterを実行
on execCIFilterWithNSImage(aNSImage, aFilterName)
  set aCIImage to convNSImageToCIimage(aNSImage) of me
  
  
set aFilter to current application’s CIFilter’s filterWithName:aFilterName
  
aFilter’s setDefaults()
  
aFilter’s setValue:aCIImage forKey:“inputImage”
  
aFilter’s setValue:2 forKey:“inputLevels”
  
set aOutImage to aFilter’s valueForKey:“outputImage”
  
  
set newNSImage to convCIimageToNSImage(aOutImage) of me
  
return newNSImage
end execCIFilterWithNSImage

–NSImageを指定パスにPNG形式で保存
on saveNSImageAtPathAsPNG(anImage, outPath)
  set imageRep to anImage’s TIFFRepresentation()
  
set aRawimg to current application’s NSBitmapImageRep’s imageRepWithData:imageRep
  
set pathString to current application’s NSString’s stringWithString:outPath
  
set newPath to pathString’s stringByExpandingTildeInPath()
  
set myNewImageData to (aRawimg’s representationUsingType:(current application’s NSPNGFileType) |properties|:(missing value))
  
set aRes to (myNewImageData’s writeToFile:newPath atomically:true) as boolean
  
return aRes –成功ならtrue、失敗ならfalseが返る
end saveNSImageAtPathAsPNG

★Click Here to Open This Script 

2017/03/21 CIImageとNSImageの相互変換

CIImageとNSImageの相互変換を行うAppleScriptです。

ファイル入出力をはじめ、さまざまな処理を行う場合にはNSImageで指定するように各種ライブラリの入出力を統一するようにしています。そのため、CIFilterを利用するような場合でもNSImageで画像データを渡すようにしています。

CIFilterを実行するサブルーチン内では、CoreImageで画像データを扱うのでCIImageで画像を渡す必要があるためCIImageに変換してFilter処理を行い、その後にNSImageに変換して結果を返すようにしています。

似たような名前のオブジェクトとして「CGImage」(CoreGraphicsの)がありますが、これはAppleScript側からは手が出ないオブジェクトに見えます。少なくとも、自分はCGImageと他フォーマットとの変換についてはやり方はわかりません。

AppleScript名:CIImageとNSImageの相互変換
– Created 2017-03-21 by Takaaki Naganoya
– 2017 Piyomaru Software
use AppleScript version "2.4"
use scripting additions
use framework "Foundation"
use framework "AppKit"
use framework "QuartzCore"
–http://piyocast.com/as/archives/4540

–Get Computer Icon (NSImage)
set anImage to current application’s NSImage’s imageNamed:(current application’s NSImageNameComputer)

set aCIImage to convNSImageToCIimage(anImage) of me
–> (CIImage)

set bNSImage to convCIimageToNSImage(aCIImage) of me
–> (NSImage)

on convCIimageToNSImage(aCIImage)
  set aRep to current application’s NSBitmapImageRep’s alloc()’s initWithCIImage:aCIImage
  
set tmpSize to aRep’s |size|()
  
set newImg to current application’s NSImage’s alloc()’s initWithSize:tmpSize
  
newImg’s addRepresentation:aRep
  
return newImg
end convCIimageToNSImage

on convNSImageToCIimage(aNSImage)
  set tiffDat to aNSImage’s TIFFRepresentation()
  
set aRep to current application’s NSBitmapImageRep’s imageRepWithData:tiffDat
  
set newImg to current application’s CIImage’s alloc()’s initWithBitmapImageRep:aRep
  
return newImg
end convNSImageToCIimage

★Click Here to Open This Script 

2015/08/19 ASOCで選択した画像をリサイズ v3

Cocoaの機能を使って指定画像を指定サイズにリサイズ(縮小Only)するAppleScriptです。

CIFilterを使って、縮小前にぼかしフィルタを、縮小後にシャープネスフィルタをかけています。

いろいろテストしていたのですが、

  「フィルタ処理するたびに画像が右上にズレるのはなぜ??」

とちょっと悩んでいました・・・どうやら、当初指定していたぼかしフィルタ(Gaussian Blur)の仕様ではないかと考え、別のぼかしフィルタ(CIBoxBlur)に変更したところ、右上への移動問題が発生しなくなりました。

処理結果に癖があるのとフィルタすると処理時間もそれなりにかかるので、Photoshopを使わない処理のほうがよい・・・ともいいにくいものがあります(「餅は餅屋」という表現がぴったり、、、)。ただし、並列処理で大量の画像を処理するような場合にはこっちを使うことになるでしょう(たぶん)。

resized10.png
▲Resized by this AppleScript

resized21.png
▲Resized by other AppleScript using Photoshop

後日談:
指定のフォルダに入っている画像を順次リサイズするように記述してみたところ、1ファイル処理したときに数秒(1〜3秒?)待たされたのがウソのように高速に(^ー^;; 1.3〜6.4MBのPNGファイルを200個処理してみたところ、所要時間55.35秒。画像1枚あたり0.28秒(MacBook Pro Retina 2012)。なかなか高速です。

AppleScript名:ASOCで選択した画像をリサイズ v3
– Created 2015-08-19 by Takaaki Naganoya
– 2015 Piyomaru Software
use AppleScript version “2.4″
use scripting additions
use framework “Foundation”
use framework “AppKit”
use framework “QuartzCore”

set targW to 450 –Target Width (Pixel)

set aPath to POSIX path of (choose file of type {“public.image”})
set aURL to current application’s |NSURL|’s fileURLWithPath:aPath

–指定したURLから画像を読み込み
set aImage to current application’s NSImage’s alloc()’s initWithContentsOfURL:aURL

–出力ファイル名を組み立てる
set aStr to current application’s NSString’s stringWithString:aPath
set bStr to (aStr’s stringByDeletingPathExtension()) as text
set outPath to bStr & “_resized” & “.png” –pngで出力

–ぼかしフィルタ
set aDict to current application’s NSDictionary’s dictionaryWithObjects:{current application’s NSNumber’s numberWithFloat:(2.0 as real)} forKeys:{“inputRadius”}
set bImage to execFilterToNSImage(aImage, “CIBoxBlur”, aDict)

–リサイズ
set cImage to resizeNSImage(targW, bImage)

–シャープフィルタ
set bDict to current application’s NSDictionary’s dictionaryWithObjects:{current application’s NSNumber’s numberWithFloat:(1.0 as real)} forKeys:{“inputSharpness”}
set dImage to execFilterToNSImage(cImage, “CISharpenLuminance”, bDict)

–ファイル保存
set aRes to saveImageRepAtPathAsPNG(dImage, outPath)

–指定画像を指定の横幅に縦横比を維持したままリサイズ
on resizeNSImage(targW, aImage)
  
  
–とりあえずImageからサイズの情報を取得
  
set sizeInfo to |size|() of aImage
  
  
set wNum to (width of sizeInfo) as integer
  
set hNum to (height of sizeInfo) as integer
  
  
  
–ターゲット横サイズをもとに、縦横のターゲットサイズを計算
  
if wNum > targW then
    –横幅がターゲットサイズよりも大きかった場合
    
set newRatioW to targW / wNum
    
set newRatioH to (hNum * newRatioW)
    
    
set newW to (wNum * newRatioW) as integer
    
set newH to (hNum * newRatioW) as integer
  else
    –横幅がターゲットサイズよりも小さかった場合はオリジナルサイズでそのまま
    
set newW to wNum
    
set newH to hNum
  end if
  
  
  
set tmpSize to current application’s NSZeroSize
  
set tmpSize’s width to newW as real
  
set tmpSize’s height to newH as real
  
  
set resImg to current application’s NSImage’s alloc()’s initWithSize:tmpSize
  
  
resImg’s lockFocus()
  
  
set aTransform to current application’s NSAffineTransform’s transform()
  
aTransform’s scaleBy:(newRatioW as real)
  
aTransform’s concat()
  
aImage’s drawAtPoint:(current application’s NSZeroPoint) fromRect:(current application’s NSZeroRect) operation:(current application’s NSCompositeCopy) fraction:1.0
  
  
resImg’s unlockFocus()
  
  
return resImg
  
end resizeNSImage

–画像を指定パスにPNG形式で保存
on saveImageRepAtPathAsPNG(anImage, outPath)
  
  
–画像のRaw画像を作成
  
set imageRep to anImage’s TIFFRepresentation()
  
set aRawimg to current application’s NSBitmapImageRep’s imageRepWithData:imageRep
  
  
–書き出しファイルパス情報を作成
  
set pathString to current application’s NSString’s stringWithString:outPath
  
set newPath to pathString’s stringByExpandingTildeInPath()
  
  
–書き出し
  
set myNewImageData to (aRawimg’s representationUsingType:(current application’s NSPNGFileType) |properties|:(missing value))
  
set aRes to (myNewImageData’s writeToFile:newPath atomically:true) as boolean
  
  
return aRes –成功ならtrue、失敗ならfalseが返る
  
end saveImageRepAtPathAsPNG

–NSImageにCIFilterを実行して返す
on execFilterToNSImage(aNSImage, aFilterName, aParamDic)
  
  
–NSImageからCIImageを生成
  
set aTiff to aNSImage’s TIFFRepresentation()
  
set aBitmap to current application’s NSBitmapImageRep’s imageRepWithData:aTiff
  
set aCIImage to current application’s CIImage’s alloc()’s initWithBitmapImageRep:aBitmap
  
  
– CIFilter をフィルタの名前で生成してフィルタ実行
  
set aFilter to current application’s CIFilter’s filterWithName:aFilterName
  
aFilter’s setDefaults() –各フィルタのパラメータはデフォルト
  
aFilter’s setValuesForKeysWithDictionary:aParamDic
  
aFilter’s setValue:aCIImage forKey:“inputImage”
  
set aOutImage to aFilter’s valueForKey:“outputImage”
  
  
  
–フィルター結果のbitmapImageRepをNSImageに変換して返す
  
set aRep to current application’s NSBitmapImageRep’s alloc()’s initWithCIImage:aOutImage
  
set outImage to current application’s NSImage’s alloc()’s initWithSize:(aRep’s |size|())
  
outImage’s addRepresentation:aRep
  
  
return outImage –NSImage
  
end execFilterToNSImage

★Click Here to Open This Script 

2014/12/09 CoreImageでフィルタしまくり

指定画像に対して、CoreImageのFilterをかけまくるAppleScriptです。オリジナルの画像は破壊せず、

 「オリジナルファイル名」_「Filter名」.jpg

の画像を(オリジナル画像と同じフォルダ内に)生成します。オリジナルはbadcharanさんのScriptですが、いろいろ(どうでもいいところを)書き換えました。主に、AppleScript Libraries用だったものを、Yosemite以降の普通のAppleScriptのフォーマットにして、ASObjCExtrasの機能を用いて簡略化。

OS X上で実行可能なフィルタのうち、リストの上の方から(いやになるまで)順にテストしてみました。Transitionなどの明らかにアニメーション用と思われるもの以外はほとんど実行可能なようです。

ただし、各フィルタのパラメータはデフォルトのままなので、各フィルタごとのパラメータを明示的に指定するような処理を付加すべきところでしょう。

現在、本Blogに画面キャプチャを掲載するさいに、Photoshopでぼかしフィルタをかけてからリサイズし、リサイズ後にシャープフィルタをかけています(びみょ〜に、JavaScriptでWebブラウザ上でサムネールを生成させたほうがいいような気もしないではないですが)。かような処理をPhotoshopなしで行う際に、このような機能が利用できることでしょう。

AppleScript名:CoreImageでフィルタしまくり
– Created 2014-12-09 by Takaaki Naganoya
– 2014 Piyomaru Software
use AppleScript version “2.4″
use scripting additions
use framework “Foundation”
use framework “ASObjCExtras”
use framework “QuartzCore”

–CIFilters (Not everything!!) From Apple’s Core Image Filter Reference
set ciList to {“CIColorInvert”, “CIBoxBlur”, “CIDiscBlur”, “CIGaussianBlur”, “CIMedianFilter”, “CIMotionBlur”, “CINoiseReduction”, “CIZoomBlur”, “CIColorMonochrome”, “CIColorPosterize”, “CIPhotoEffectChrome”, “CISepiaTone”, “CISharpenLuminance”, “CIUnsharpMask”, “CIKaleidoscope”}

–画像を選択
set aPath to choose file of type {“public.image”}

–すべてのフィルタを実行
repeat with i in ciList
  set j to contents of i
  
set aRes to convAsFilteredJPEG(aPath, j) of me
end repeat

–CIFilterをかけたJPEG画像を生成
–参照:http://ashplanning.blogspot.jp/ のうちのどこか
on convAsFilteredJPEG(aPath, aFilterName)
  
  
–aliasをURL(input)とPOSIX path(output) に変換
  
set aURL to (current application’s SMSFord’s URLFrom:aPath) –Input
  
set aPOSIX to (POSIX path of aPath) & “_” & aFilterName & “.jpg” –Output
  
  
–CIImageを生成
  
set aCIImage to current application’s CIImage’s alloc()’s initWithContentsOfURL:aURL
  
  
– CIFilter をフィルタの名前で生成
  
set aFilter to current application’s CIFilter’s filterWithName:aFilterName
  
aFilter’s setDefaults() –各フィルタのパラメータはデフォルト
  
  
–Filterを実行
  
aFilter’s setValue:aCIImage forKey:“inputImage”
  
set aOutImage to aFilter’s valueForKey:“outputImage”
  
  
– NSBitmapImageRep を CIImage から生成
  
set aRep to current application’s NSBitmapImageRep’s alloc()’s initWithCIImage:aOutImage
  
  
– NSBitmapImageRep から JPEG データを取得
  
set jpegData to aRep’s representationUsingType:(current application’s NSJPEGFileType) |properties|:(missing value)
  
  
– ファイルに保存
  
set fsRes to jpegData’s writeToFile:aPOSIX atomically:true
  
return fsRes as boolean
  
end convAsFilteredJPEG

★Click Here to Open This Script