मैंने निम्नलिखित आकार बदलने वाले एल्गोरिदम लिखा है जो छवि को ऊपर या नीचे सही ढंग से स्केल कर सकता है। यह बहुत धीमी है हालांकि प्रत्येक पाश पर वजन की सरणी के माध्यम से आंतरिक पुनरावृत्ति के कारण।स्प्लिट आकार दो एल्गोरिदम को दो पासों में विभाजित करें
मुझे काफी यकीन है कि मैं एल्गोरिदम को दो पासों में विभाजित करने में सक्षम होना चाहिए जैसा कि आप दो पास गॉसियन ब्लर के साथ करेंगे जो परिचालन जटिलता को काफी कम करेगा और प्रदर्शन को तेज करेगा। दुर्भाग्य से मैं इसे काम नहीं कर सकता। क्या कोई मदद करने में सक्षम होगा?
Parallel.For(
startY,
endY,
y =>
{
if (y >= targetY && y < targetBottom)
{
Weight[] verticalValues = this.verticalWeights[y].Values;
for (int x = startX; x < endX; x++)
{
Weight[] horizontalValues = this.horizontalWeights[x].Values;
// Destination color components
Color destination = new Color();
// This is where there is too much operation complexity.
foreach (Weight yw in verticalValues)
{
int originY = yw.Index;
foreach (Weight xw in horizontalValues)
{
int originX = xw.Index;
Color sourceColor = Color.Expand(source[originX, originY]);
float weight = yw.Value * xw.Value;
destination += sourceColor * weight;
}
}
destination = Color.Compress(destination);
target[x, y] = destination;
}
}
});
वजन और सूचकांक निम्नानुसार गणना की जाती है। प्रत्येक आयाम के लिए एक:
/// <summary>
/// Computes the weights to apply at each pixel when resizing.
/// </summary>
/// <param name="destinationSize">The destination section size.</param>
/// <param name="sourceSize">The source section size.</param>
/// <returns>
/// The <see cref="T:Weights[]"/>.
/// </returns>
private Weights[] PrecomputeWeights(int destinationSize, int sourceSize)
{
IResampler sampler = this.Sampler;
float ratio = sourceSize/(float)destinationSize;
float scale = ratio;
// When shrinking, broaden the effective kernel support so that we still
// visit every source pixel.
if (scale < 1)
{
scale = 1;
}
float scaledRadius = (float)Math.Ceiling(scale * sampler.Radius);
Weights[] result = new Weights[destinationSize];
// Make the weights slices, one source for each column or row.
Parallel.For(
0,
destinationSize,
i =>
{
float center = ((i + .5f) * ratio) - 0.5f;
int start = (int)Math.Ceiling(center - scaledRadius);
if (start < 0)
{
start = 0;
}
int end = (int)Math.Floor(center + scaledRadius);
if (end > sourceSize)
{
end = sourceSize;
if (end < start)
{
end = start;
}
}
float sum = 0;
result[i] = new Weights();
List<Weight> builder = new List<Weight>();
for (int a = start; a < end; a++)
{
float w = sampler.GetValue((a - center)/scale);
if (w < 0 || w > 0)
{
sum += w;
builder.Add(new Weight(a, w));
}
}
// Normalise the values
if (sum > 0 || sum < 0)
{
builder.ForEach(w => w.Value /= sum);
}
result[i].Values = builder.ToArray();
result[i].Sum = sum;
});
return result;
}
/// <summary>
/// Represents the weight to be added to a scaled pixel.
/// </summary>
protected class Weight
{
/// <summary>
/// The pixel index.
/// </summary>
public readonly int Index;
/// <summary>
/// Initializes a new instance of the <see cref="Weight"/> class.
/// </summary>
/// <param name="index">The index.</param>
/// <param name="value">The value.</param>
public Weight(int index, float value)
{
this.Index = index;
this.Value = value;
}
/// <summary>
/// Gets or sets the result of the interpolation algorithm.
/// </summary>
public float Value { get; set; }
}
/// <summary>
/// Represents a collection of weights and their sum.
/// </summary>
protected class Weights
{
/// <summary>
/// Gets or sets the values.
/// </summary>
public Weight[] Values { get; set; }
/// <summary>
/// Gets or sets the sum.
/// </summary>
public float Sum { get; set; }
}
प्रत्येक आईरसप्लर दिए गए सूचकांक के आधार पर वजन की उचित श्रृंखला प्रदान करता है। निम्नानुसार bicubic resampler काम करता है।
/// <summary>
/// The function implements the bicubic kernel algorithm W(x) as described on
/// <see href="https://en.wikipedia.org/wiki/Bicubic_interpolation#Bicubic_convolution_algorithm">Wikipedia</see>
/// A commonly used algorithm within imageprocessing that preserves sharpness better than triangle interpolation.
/// </summary>
public class BicubicResampler : IResampler
{
/// <inheritdoc/>
public float Radius => 2;
/// <inheritdoc/>
public float GetValue(float x)
{
// The coefficient.
float a = -0.5f;
if (x < 0)
{
x = -x;
}
float result = 0;
if (x <= 1)
{
result = (((1.5f * x) - 2.5f) * x * x) + 1;
}
else if (x < 2)
{
result = (((((a * x) + 2.5f) * x) - 4) * x) + 2;
}
return result;
}
}
मौजूदा एल्गोरिदम द्वारा आकार की गई छवि का एक उदाहरण यहां दिया गया है। आउटपुट सही है (नोट करें कि चांदी की शीन संरक्षित है)।
मूल छवि
छवि bicubic रीसैंपलर का उपयोग कर आकार में आधा कर दिया।
कोड एक बहुत बड़ा library कि मैं corefx लिए इमेज प्रोसेसिंग जोड़ने के लिए लिख रहा हूँ का हिस्सा है।
इंडेक्स और वजन मूल्य क्या हैं? इसके बिना रिकर्सन उपखंड की गणना करने का कोई तरीका नहीं है ... अन्य तो क्रूर बल ... और केवल तभी कुछ गुणों को पूरा किया जाता है ... फ़िल्टरिंग से पहले और बाद में नमूना छवि साझा करना भी एक अच्छा विचार होगा, इसलिए कुछ ऐसा है तुलना करें ... – Spektre
@Spektre मैंने प्रश्न के लिए बहुत अधिक जानकारी जोड़ दी है। यदि आपको कुछ और चाहिए तो कृपया मुझे बताएं। –
अच्छी तरह से यह द्वि-क्यूबिक है (एक मनमानी दृढ़ संकल्प नहीं जिसे मैंने आपके कोड से पहले गहराई से देखा है) तो यह रिकर्सन उपखंड द्वारा हल नहीं किया जा सकता है। इसके बजाए इसे 2x1D समस्या में विभाजित किया जा सकता है, लेकिन मुझे यकीन नहीं है कि यह तेज़ होगा (आजकल कंप्यूटर पर) फिर 2 डी पुन: नमूनाकरण करें। इसके बारे में कुछ परीक्षण करना है लेकिन इसके लिए सोमवार तक इसका समय नहीं होगा। – Spektre