سؤال

أنا بناء موقع على شبكة الإنترنت من أجل النادي الذي هو جزء من المنظمة الأم.أنا تحميل (الإمتصاص ;) ) الصور حيث وضع على الصفحات الشخصية للأم المنظمة أن تظهر على الصفحة الخاصة بي.ولكن موقعه على الانترنت لطيف خلفية بيضاء ، موقع الويب الخاص بي لديه لطيفة التدرج الرمادي على خلفية.هذا لا يتطابق بشكل جيد.لذا كانت فكرتي لتحرير الصور قبل حفظها على الخادم.

أنا باستخدام+ GDI لتعزيز الصور عند استخدام طريقة MakeTransparent النقطية ، و لا تفعل ما يفترض القيام به, ولكن لا يزال لدي هذه أبيض jpeg التحف في كل مكان.القطع الأثرية يجعل الصورة سيئة للغاية ، أنا أفضل حالا لا يجعل الصورة شفافة و تركها بيضاء ولكن هذا القبيح حقا على موقع الويب الخاص بي.يمكنني دائما في حدود لطيفة مع خلفية بيضاء بالطبع, ولكن بدلا من ذلك تغيير خلفية شفافة.

لذلك أنا أتساءل عما إذا كان يمكنني إزالة بعض بسيطة JPEG الأثرية في C#.وقد أي شخص من أي وقت مضى فعلت هذا من قبل ؟

شكرا على وقتك.

مثال الصورة:

TB-5404

تحويل الصورة:

TB-5404 transformed

هل كانت مفيدة؟

المحلول

حسنا، أنا حاولت ما هو أبعد ما يكون عن الكمال، ولكن أنا الرقم قد يكون من المفيد لشخص آخر.

ولقد حصلت على:

والمشاكل التي واجهتها: الظلال الآن ما يكفي من "أوف وايت" أن من الصعب أن السيارات تحويلها، وحتى لو فعلت ظل ستظل في الصورة نفسها. على مرأى ومسمع من الشيء أعلى ... المحور، هو أيضا أقرب إلى خارج بيضاء ثم البتات مكافحة مستعارة. هناك 3-7 بقع بيضاء في الصورة التي لا ترتبط بأي من زوايا الأولية؛ وأخيرا لا يزال هناك قليلا من اللون الأبيض على حواف (ربما يمكن التخلص منه عن طريق اللف رمز، ولكن ليس دون اقلاعها جزء من رأس وهج.

وC # رمز غير فعالة:

    static void Main()
    {
        Bitmap bmp=new Bitmap("test.jpg");

        int width = bmp.Width;
        int height = bmp.Height;
        Dictionary<Point, int> currentLayer = new Dictionary<Point, int>();
        currentLayer[new Point(0, 0)] = 0;
        currentLayer[new Point(width - 1, height - 1)] = 0;
        while (currentLayer.Count != 0)
        {
            foreach (Point p in currentLayer.Keys)
                bmp.SetPixel(p.X, p.Y, Color.Black);
            Dictionary<Point, int> newLayer = new Dictionary<Point, int>();
            foreach (Point p in currentLayer.Keys)
                foreach (Point p1 in Neighbors(p, width, height))
                    if (Distance(bmp.GetPixel(p1.X, p1.Y), Color.White) < 40)
                        newLayer[p1] = 0;
            currentLayer = newLayer;
        }

        bmp.Save("test2.jpg");
    }

    static int Distance(Color c1, Color c2)
    {
        int dr = Math.Abs(c1.R - c2.R);
        int dg = Math.Abs(c1.G - c2.G);
        int db = Math.Abs(c1.B - c2.B);
        return Math.Max(Math.Max(dr, dg), db);
    }

    static List<Point> Neighbors(Point p, int maxX, int maxY)
    {
        List<Point> points=new List<Point>();
        if (p.X + 1 < maxX) points.Add(new Point(p.X + 1, p.Y));
        if (p.X - 1 >= 0) points.Add(new Point(p.X - 1, p.Y));
        if (p.Y + 1 < maxY) points.Add(new Point(p.X, p.Y + 1));
        if (p.Y - 1 >= 0) points.Add(new Point(p.X, p.Y - 1));
        return points;
    }

وكود يعمل من خلال البدء برصيد نقطتين. وضع لهم إلى الأسود، ومن ثم التحقق لمعرفة ما إذا كان أي الجيران بالقرب منهم بالقرب أبيض؛ إذا كانت انهم تضاف إلى قائمة التي يتم بعد ذلك تنفيذ ضد. في نهاية المطاف نفدت بكسل البيضاء للتغيير.

وكبديل لذلك، قد ترغب في النظر في إعادة تصميم الموقع لاستخدام خلفية بيضاء.

نصائح أخرى

وحلقة خلال كل بكسل في الصورة، إذا R، G و B هو أعلى من، مثلا، 230 ثم استبدال اللون مع اللون المطلوب (أو شفافة). ربما الوزن اللون الجديد اعتمادا على مدى من الأبيض "الحقيقي" اللون القديم.

ويتوقع أن تحصل مشاكل إذا كانت الصورة الفعلية بيضاء أيضا، otherwhise سوف ينتهي بك الأمر مع STORMTROOPER الرمادي:)

سوف لا تكون قادرة على القيام بذلك تلقائيا مع أي شيء مثل 100 ٪ من الدقة.

والسبب في ذلك هو أن المعلومات لديك هو اللون الذي كنت تعرف أن بعض بكسل في الصورة هي محاولة مزيج جيد مع.فقط بعض بكسل في الصورة سوف يكون في الواقع باستخدام الألوان في أو قريبة من هذه القيمة لأغراض التظليل في الخلفية ، والبعض الآخر سوف يكون باستخدام (في حالة الأبيض) لأن الكائن الفعلي تمثل في الواقع الأبيض (لعنة دقة هذه الإمبراطورية العاصفة).

نوع من آلة متطورة التعلم لكشف ما هو الذي هو مشكلة مثيرة للاهتمام المجال, و قد يكون المشروع متعة بالنسبة لك ولكنها بالتأكيد لن تجعل بسرعة حل المشكلة فورا.

مشكلة أخرى لديك هو أنه حتى لو تمكنت من الكشف مع موثوقية جيدة تلك المناطق من الصورة التي يحاول الذوبان في الأرض مرة أخرى سيكون لديك قضايا 'unblending' لهم ثم reblending لهم في لون الخلفية ما لم الألوان معقولة متوافق.في هذه الحالة الرمادية الخاصة بك قد عمل منذ ذلك واسع الطيف اللون مثل الأبيض.

الأسلوب الذي تريد استخدامه على النحو التالي:

  • استخدام ملء الفيضانات خوارزمية لتحديد من حواف الصورة إلى الداخل في كل بكسل في x%(1) من المعروف خلفية اللون.
  • بالنسبة لأولئك بكسل ضبط قناة ألفا إلى قيمة كنسبة من مباراة إلى اللون الأصلي والقضاء على لون الزهر الذي كان المرتبطة به.
    • حتى إذا ظل هو RGB قيمة a,b,c بكسل+5,b,c-7 ثم النتيجة RGBA 5,0,0,((a+b+c-7)/(a+b+c)*256)(1)
  • المركب هذا مزج ألفا الصورة أكثر من الألم متر من جديد الى الوراء في الميدان colur.
  • تجعل النتيجة مع أي قناة ألفا كما في صورة جديدة.

هذا سوف لا يزال لديك مشاكل لكائنات اللون على مقربة من أي لون الخلفية.* في حالة الأصلية ثم قد يكون هذا التظليل يتم استخدامه يعني الوجود الكائن ، مثل الفيضانات ملء سوف 'غزو' داخل الصورة.* في الحالة الأخيرة فإن الصورة الناتجة سوف تفقد تعريف الكائن و لا خفية التظليل ، يسلط الضوء أو مجرد خطوط الحاضر للإشارة إلى المكان الكائن ينتهي الأرض مرة أخرى ينتهي.

هذا هو أول عصيب جدا التقريب ولكن قد يغطي نسبة معقولة من الهدف الخاص بك.تلك الصور مع شفاف مغلق تماما الثقوب (مثل الفجوات في القوس الخارجي في المثال الخاص بك) ليس من المرجح أن تعمل من أي وقت مضى بشكل جيد بطريقة تلقائية منذ الخوارزمية سوف تكون قادرة على التمييز بين الأبيض الثقوب البيضاء العاصفة.
قد ترغب في جعل لك خوارزمية تسليط الضوء على مناطق من الصورة انها تخطط على reblending والسماح بسيطة مختارة من المناطق تشمل/استبعاد (باستخدام أداة التحديد العصا السحرية من Pain.Net كمثال على كيفية القيام بذلك إذا كنت تريد أن تكون نزوة ، مما يسمح بسيطة لكل بكسل اختيار أقل مقدما الجهد.


  1. قيمة x سوف يكون شيئا كنت لحن - قد يكون ذلك استنادا إلى بعض جوانب الصورة (تقول نسبة من الصورة التي هي قريبة من الأرض مرة أخرى اللون) يمكنك قرص تلقائيا.
  2. علما أن هذه الصيغ يفترض قريبة إلى اللون الأبيض ، على مقربة من الأسود تريد عكس

ونهج واحد آخر على أساس الحوار تعليق:

static void Main()
{
    Bitmap mask = new Bitmap(@"mask.bmp");
    Bitmap bmp=new Bitmap(@"test.jpg");
    int width = bmp.Width;
    int height = bmp.Height;

    for(int x=0; x<width; x++)
        for (int y = 0; y < height; y++)
            if (mask.GetPixel(x, y).R < 250)
                bmp.SetPixel(x,y,mask.GetPixel(x,y));
    bmp.Save(@"test3.jpg");
}

وقناع المعطى:

ويمكنك الحصول على النتيجة:

ومع حدود قناع تنظيف ارتفاعا طفيفا في Paint.NET مع مكافحة التعرج تعطيل. مرة أخرى، انها لا تنطبق إلا إذا كان يمكنك تمييز أي الحدود يتم استخدامه ... لكنها لم تتحول بشكل جيد ... باستثناء الأخضر ...

وسيكون لديك للتعامل مع ظلال من البيض أيضا. ربما عندما جعلوا iamges ليل في البداية وتعيين لون الخلفية، كان هناك بعض تنعيم، ثم عند حفظ جي بي جي، لن يتم الحفاظ على جميع الألوان تماما. حتى إذا كنت ترغب بجعل لون معين شفافة، وانها لن تحصل على كل ظلال من هذا اللون الذي سيترك العديد من القطع الأثرية. كنت بحاجة الى شيء من شأنها أن تفعل الشفافية تتناسب مع مدى قرب اللون هو اللون الرئيسي الخاص بك. هذا قد يكون شيئا أسهل للقيام كبرنامج نصي دفعة في شيء مثل فوتوشوب، ولكن أنا لا أعرف إذا كان هذا هو ما كنت تحتاج إلى القيام به في الوقت الحقيقي.

وليس هناك (سهلة عن بعد) وسيلة للتعامل مع هذه المشكلة برمجيا. المناطق البيضاء قطعة أثرية ذ حول حافة الصورة هي نتيجة بكسل التي هي بيضاء تقريبا ولكن ليس تماما، حتى لا تلتقط تأثير الشفافية. هناك أيضا بضعة بقع على القدح قناع / القهوة التي هي بيضاء نقية، بحيث تصبح شفافة، وبالتالي الرمادي.

وأفضل رهان هو الاتصال بمشرف الموقع الأصلي ومعرفة ما اذا كان يمكن أن نرسل لك الصور الأصلية، ونأمل في الفوتوشوب أو شكل آخر حيث يتم الاحتفاظ طبقات الأصلي بشكل منفصل. هل يمكن بعد ذلك إعادة توليد الصور في الشكل الذي يحافظ على الشفافية الأصلية (PNG أو شيء من هذا القبيل) وإلا يستخدم التدرج للحصول على الخلفية (أنه سيكون صعبا للغاية للحصول على هذا الحق، وبما انك لا تعرف بالضبط أين داخل التدرج سيتم تقديم الصورة).

وكنت أذهب مع بعض نوع من الحدود حول الصور، كما اقترحتم.

والشكر للجميع إجاباتك .. كل اقتراحات جيدة ..

وهنا هو ما يطبخ أمس:

public const int PIXEL_REGION = 60;
public const int TRANSPARENT_DISTANCE = 60;
public static readonly Color TRANSPARENT_COLOR = Color.White;

private System.Drawing.Image ProcessImage(System.Drawing.Image image)
{
    Bitmap result = new Bitmap(image.Width, image.Height);

    Bitmap workImage = new Bitmap(image);

    for (int x = 0; x < image.Width; x++)
    {
        for (int y = 0; y < image.Height; y++)
        {
            Color color = workImage.GetPixel(x, y);

            if (x < PIXEL_REGION || x > image.Width - PIXEL_REGION || y < PIXEL_REGION || y > image.Height - PIXEL_REGION)
            {
                double distance = CalculateColourDistance(TRANSPARENT_COLOR, color);

                if(distance < TRANSPARENT_DISTANCE)
                {
                    result.SetPixel(x, y, Color.Transparent);
                    continue;
                }
            }

            result.SetPixel(x, y, color);
        }
    }

    return result;
}

private double CalculateColourDistance(Color c1, Color c2)
{
    int a = c2.A - c1.A;
    int r = c2.R - c1.R;
    int g = c2.G - c1.G;
    int b = c2.B - c1.B;

    return Math.Sqrt(Math.Pow(a, 2) + Math.Pow(r, 2) + Math.Pow(g, 2) + Math.Pow(b, 2));
}

وانها ليست رمز الأكثر جمالا في الكتاب، ولكن ما تقوم به، هو كل بكسل في المنطقة بكسل هو حساب المسافة بين Color.White ولون بلدي، وعندما يكون أقل من المسافة المحددة مسبقا وسوف تكون ملونة شفافة ..

وهذه قطعة من رمز تنتج نتيجة التالية:

وانها ليست سيئة واعتبارها لكم .. لكنه لا يزال يمص:)

ولدي خدعة واحدة حتى كمي والتي سوف أطلعكم على اللاعبين وكذلك إذا نجحت ...

وهنا هي محاولة فاشلة أخرى؛)

وكان لي فكرة .. الأفلام استخدام greenscreen تشبه، لماذا لا تستخدم تراكب الأخضر لصورة بلادي .. حتى هنا هو تراكب:

والنتائج:

وهكذا تعلمت درسا قيما آخر حول ضغط PNG .. كما أنني حاولت ذلك مع السجناء، ولكن ما أنا دائما في نهاية المطاف مع حد أخضر .. يمكنني محاولة لمحو ذلك، ولكن ربما أنا فقط يجب ترك الأمر في البيضاء الخلفية، وضع بعض الحدود سخيفة من حوله، وينبغي القيام به معها ...

وآه حسنا ..؛)

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top