मैं कुछ प्रगति की है, और मैं काफी यह मेरा प्रश्न का उत्तर पर विचार , हालांकि कुछ चीजें एक अलग हैं और मैं टी नहीं करता हूं इस विधि को हिंक करें बहुत तेज है। मुझे यह कोड देखने के लिए किसी से भी सुनना अच्छा लगेगा कि इस कोड को तेज़ी से कैसे बनाया जाए। नीचे दिए गए, ऐसा लगता है कि छवि का आकार बदलने में सबसे अधिक समय लग रहा है, मुझे ओवेराइड आउटपुट इमेज सेक्शन में कॉल का एक टन मिलता है और मुझे नहीं पता कि यह क्यों है। दुर्भाग्य से जब मैं नीचे लाप्लाशियन पिरामिड फ़ंक्शन चलाता हूं, तो 275x300 फ़ोटो पर पूरा होने में लगभग 5 सेकंड लगते हैं। यह सिर्फ अच्छा नहीं है, और मैं इसे कम करने के तरीके के रूप में कुछ नुकसान में हूं। मेरा संदेह यह है कि पुनर्विक्रय फ़िल्टर अपराधी है। हालांकि मुझे यह जानने के लिए पर्याप्त जानकारी नहीं है कि इसे कैसे तेजी से बनाया जाए।
पहले, कस्टम फिल्टर:
यह पहले एक एक सरल rescaling करके एक छवि आकार बदलता है। मुझे लगता है कि यह इस मामले में पुनर्विक्रय की सबसे अच्छी तकनीक है क्योंकि जो कुछ भी किया जाता है वह आकार बदलते समय पिक्सेल की प्रतिकृति है।
[ ][ ][x][ ] ----->[ ][ ][ ][ ][x][x][ ][ ]
(साइमन Gladman को विचार के लिए इस पर धन्यवाद)
public class ResampleFilter: CIFilter
{
var inputImage : CIImage?
var inputScaleX: CGFloat = 1
var inputScaleY: CGFloat = 1
let warpKernel = CIWarpKernel(string:
"kernel vec2 resample(float inputScaleX, float inputScaleY)" +
" { " +
" float y = (destCoord().y/inputScaleY); " +
" float x = (destCoord().x/inputScaleX); " +
" return vec2(x,y); " +
" } "
)
override public var outputImage: CIImage!
{
if let inputImage = inputImage,
kernel = warpKernel
{
let arguments = [inputScaleX, inputScaleY]
let extent = CGRect(origin: inputImage.extent.origin,
size: CGSize(width: inputImage.extent.width*inputScaleX,
height: inputImage.extent.height*inputScaleY))
return kernel.applyWithExtent(extent,
roiCallback:
{
(index,rect) in
let sampleX = rect.origin.x/self.inputScaleX
let sampleY = rect.origin.y/self.inputScaleY
let sampleWidth = rect.width/self.inputScaleX
let sampleHeight = rect.height/self.inputScaleY
let sampleRect = CGRect(x: sampleX, y: sampleY, width: sampleWidth, height: sampleHeight)
return sampleRect
},
inputImage : inputImage,
arguments : arguments)
}
return nil
}
}
यह: उदाहरण के लिए, अगर हम पिक्सल के निम्नलिखित ब्लॉक है और एक 2.0 पैमाने करते हैं, तो मानचित्रण की तरह लग रहा है निम्नलिखित एक साधारण अंतर मिश्रण है।
public class DifferenceOfImages: CIFilter
{
var inputImage1 : CIImage? //Initializes input
var inputImage2 : CIImage?
var kernel = CIKernel(string: //The actual custom kernel code
"kernel vec4 Difference(__sample image1,__sample image2)" +
" { " +
" float colorR = image1.r - image2.r; " +
" float colorG = image1.g - image2.g; " +
" float colorB = image1.b - image2.b; " +
" return vec4(colorR,colorG,colorB,1); " +
" } "
)
var extentFunction: (CGRect, CGRect) -> CGRect =
{ (a: CGRect, b: CGRect) in return CGRectZero }
override public var outputImage: CIImage!
{
guard let inputImage1 = inputImage1,
inputImage2 = inputImage2,
kernel = kernel
else
{
return nil
}
//apply to whole image
let extent = extentFunction(inputImage1.extent,inputImage2.extent)
//arguments of the kernel
let arguments = [inputImage1,inputImage2]
//return the rectangle that defines the part of the image that CI needs to render rect in the output
return kernel.applyWithExtent(extent,
roiCallback:
{ (index, rect) in
return rect
},
arguments: arguments)
}
}
अब कुछ समारोह परिभाषा के लिए
:
इस समारोह बस छवि पर एक गाऊसी कलंक करता है, बर्ट & Adelson के पत्र में वर्णित के रूप में ही 5 नल फिल्टर के अनुसार। यह सुनिश्चित नहीं है कि अजीब सीमावर्ती पिक्सल से कैसे छुटकारा पाना है जो अतिरिक्त प्रतीत होता है।
public func GaussianFilter(ciImage: CIImage) -> CIImage
{
//5x5 convolution to image
let kernelValues: [CGFloat] = [
0.0025, 0.0125, 0.0200, 0.0125, 0.0025,
0.0125, 0.0625, 0.1000, 0.0625, 0.0125,
0.0200, 0.1000, 0.1600, 0.1000, 0.0200,
0.0125, 0.0625, 0.1000, 0.0625, 0.0125,
0.0025, 0.0125, 0.0200, 0.0125, 0.0025 ]
let weightMatrix = CIVector(values: kernelValues,
count: kernelValues.count)
let filter = CIFilter(name: "CIConvolution5X5",
withInputParameters: [
kCIInputImageKey: ciImage,
kCIInputWeightsKey: weightMatrix])!
let final = filter.outputImage!
let rect = CGRect(x: 0, y: 0, width: ciImage.extent.size.width, height: ciImage.extent.size.height)
return final.imageByCroppingToRect(rect)
}
यह फ़ंक्शन बस अनुकरण के उपयोग को सरल बनाता है। आप नई छवि का लक्ष्य आकार निर्दिष्ट कर सकते हैं।स्केल पैरामीटर आईएमओ सेट करने के बजाय यह सौदा करना आसान हो जाता है।
public func resampleImage(inputImage: CIImage, sizeX: CGFloat, sizeY: CGFloat) -> CIImage
{
let inputWidth : CGFloat = inputImage.extent.size.width
let inputHeight : CGFloat = inputImage.extent.size.height
let scaleX = sizeX/inputWidth
let scaleY = sizeY/inputHeight
let resamplefilter = ResampleFilter()
resamplefilter.inputImage = inputImage
resamplefilter.inputScaleX = scaleX
resamplefilter.inputScaleY = scaleY
return resamplefilter.outputImage
}
यह फ़ंक्शन केवल अंतर फ़िल्टर के उपयोग को सरल बनाता है। बस ध्यान दें कि यह
imageOne - ImageTwo
है।
public func Difference(imageOne:CIImage,imageTwo:CIImage) -> CIImage
{
let generalFilter = DifferenceOfImages()
generalFilter.inputImage1 = imageOne
generalFilter.inputImage2 = imageTwo
generalFilter.extentFunction = { (fore, back) in return back.union(fore)}
return generalFilter.outputImage
}
यह फ़ंक्शन प्रत्येक पिरामिड के स्तर आयामों की गणना करता है, और उन्हें एक सरणी में संग्रहीत करता है। बाद में उपयोगी।
public func LevelDimensions(image: CIImage,levels:Int) -> [[CGFloat]]
{
let inputWidth : CGFloat = image.extent.width
let inputHeight : CGFloat = image.extent.height
var levelSizes : [[CGFloat]] = [[inputWidth,inputHeight]]
for j in 1...(levels-1)
{
let temp = [floor(inputWidth/pow(2.0,CGFloat(j))),floor(inputHeight/pow(2,CGFloat(j)))]
levelSizes.append(temp)
}
return levelSizes
}
अब अच्छी चीजों पर: यह एक गॉसियन पिरामिड को स्तरों की एक निश्चित संख्या बनाता है।
public func GaussianPyramid(image: CIImage,levels:Int) -> [CIImage]
{
let PyrLevel = LevelDimensions(image, levels: levels)
var GauPyr : [CIImage] = [image]
var I : CIImage
var J : CIImage
for j in 1 ... levels-1
{
J = GaussianFilter(GauPyr[j-1])
I = resampleImage(J, sizeX: PyrLevel[j][0], sizeY: PyrLevel[j][1])
GauPyr.append(I)
}
return GauPyr
}
अंत में, इस समारोह का स्तर की दी गई संख्या के साथ Laplacian पिरामिड बनाता है। ध्यान दें कि पिरामिड कार्यों दोनों में, प्रत्येक स्तर को ऐरे में संग्रहीत किया जाता है।
public func LaplacianPyramid(image:CIImage,levels:Int) -> [CIImage]
{
let PyrLevel = LevelDimensions(image, levels:levels)
var LapPyr : [CIImage] = []
var I : CIImage
var J : CIImage
J = image
for j in 0 ... levels-2
{
let blur = GaussianFilter(J)
I = resampleImage(blur, sizeX: PyrLevel[j+1][0], sizeY: PyrLevel[j+1][1])
let diff = Difference(J,imageTwo: resampleImage(I, sizeX: PyrLevel[j][0], sizeY: PyrLevel[j][1]))
LapPyr.append(diff)
J = I
}
LapPyr.append(J)
return LapPyr
}
आप को देखा है यह: https://developer.apple.com/reference/metalperformanceshaders/mpsimagegaussianpyramid –
मेरे पास है, लेकिन मैं वास्तव में अगर वहाँ था कस्टम फ़िल्टर उपयोग करने से पहले एक विकल्प है कि मैं क्या चाहते हैं देखना चाहता था । ये चीजें छवि प्रसंस्करण में इतनी असामान्य नहीं हैं, इसलिए मुझे लगा कि सेब के पहले से निर्मित एक तरीका होगा। –
मुझे यकीन नहीं है कि इसमें आपके पास आवश्यक सभी कार्य हैं, लेकिन आप 'फ्रेमवर्क को तेज करें' https://developer.apple.com/videos/play/wwdc2013/713/ – juanjo