AMcoder - javascript, python, java, html, php, sql

Թույլ տալ, որ Պատկերը հասանելի լինի մի քանի շղթաներով

Ես փորձում եմ պատկերների մշակում կատարել C#-ով: Ես ուզում եմ օգտագործել որոշ թելեր՝ իմ պատկերի մի քանի գոտիների վրա զուգահեռ հաշվարկներ կատարելու համար: Թելերը իրականում ստանում և կարգավորում են պիքսելներ Bitmap օբյեկտում: Բացարձակապես ոչ մի հնարավորություն չկա, որ 2 թեմա մուտք գործի նույն պիքսելը, այնպես որ խնդիրը դա չէ:

Խնդիրն այն է, որ C#-ն ինձ թույլ չի տալիս մի քանի թեմա սկսել նույն Bitmap օբյեկտի վրա, նույնիսկ եթե ես վստահ եմ, որ նույն պիքսելը չի ​​կարդացվի և չի փոփոխվի միաժամանակ:

Կա՞ որևէ միջոց C#-ից խուսափելու այս սխալը բարձրացնելու համար: Կամ պարզապես անհնար է մի քանի թելեր գործարկել իմ Bitmap օբյեկտի վրա:

Շնորհակալություն,

Պիեռ-Օլիվյե


  • Ձեր տերմինաբանությունը շփոթեցնող է, ինչպե՞ս եք թել վարում օբյեկտի վրա: Ի՞նչն է խանգարում ձեր շղթաներին մուտք գործել ընդհանուր փոփոխական: Խնդրում ենք տեղադրել այն կոդը, որն ասում եք, որ չի աշխատում: 01.02.2014
  • C# թելերով պատկերների մշակման հնարավոր կրկնօրինակը 01.02.2014
  • Այս թեման խորհուրդ է տալիս անվտանգ դարձնել մուտքը bitmap օբյեկտի շարանը: Ես իրականում ուզում եմ կոտրել այս անվտանգությունը, քանի որ, ինչպես ասացի այն հարցին, բացարձակապես անհնար է, որ նույն պիքսելը հասանելի լինի և փոփոխվի տարբեր թելերով: 01.02.2014
  • Այն կապ չունի C#-ի կամ պիքսելների հետ, Image դասը թույլ չի տալիս միաժամանակ երկու շղթա մուտք գործել bitmap: Սա հիմնարար սահմանափակում է, որը էական է, որպեսզի խուսափեք կոդի միկրո կողպման հետևանքով մահից, դուք ստիպված կլինեք աշխատել դրա շուրջ: 01.02.2014

Պատասխանները:


1

Օգտագործելով LockBits (որը Նաև շատ ավելի արագ է, քան GetPixel & SetPixel-ը), դուք կարող եք պատճենել պատկերի պիքսելները բուֆերում, զուգահեռ թելեր անցկացնել դրա վրա և այնուհետև պատճենել բուֆերը:

Ահա աշխատանքային օրինակ.

void Test()
{
    string inputFile = @"e:\temp\a.jpg";
    string outputFile = @"e:\temp\b.jpg";

    Bitmap bmp = Bitmap.FromFile(inputFile) as Bitmap;

    var rect = new Rectangle(0, 0, bmp.Width, bmp.Height);
    var data = bmp.LockBits(rect, ImageLockMode.ReadWrite, bmp.PixelFormat);
    var depth = Bitmap.GetPixelFormatSize(data.PixelFormat) / 8; //bytes per pixel

    var buffer = new byte[data.Width * data.Height * depth];

    //copy pixels to buffer
    Marshal.Copy(data.Scan0, buffer, 0, buffer.Length);

    Parallel.Invoke(
        () => {
            //upper-left
            Process(buffer, 0, 0, data.Width / 2, data.Height / 2, data.Width, depth);
        },
        () => {
            //lower-right
            Process(buffer, data.Width / 2, data.Height / 2, data.Width, data.Height, data.Width, depth);
        }
    );

    //Copy the buffer back to image
    Marshal.Copy(buffer, 0, data.Scan0, buffer.Length);

    bmp.UnlockBits(data);

    bmp.Save(outputFile, ImageFormat.Jpeg);
}

void Process(byte[] buffer, int x, int y, int endx, int endy, int width, int depth)
{
    for (int i = x; i < endx; i++)
    {
        for (int j = y; j < endy; j++)
        {
            var offset = ((j * width) + i) * depth;
            // Dummy work    
            // To grayscale (0.2126 R + 0.7152 G + 0.0722 B)
            var b = 0.2126 * buffer[offset + 0] + 0.7152 * buffer[offset + 1] + 0.0722 * buffer[offset + 2];
            buffer[offset + 0] = buffer[offset + 1] = buffer[offset + 2] = (byte)b;
        }
    }
}

Մուտքագրեք պատկեր՝

մուտքագրեք պատկերի նկարագրությունը այստեղ

Ելքային պատկեր՝

մուտքագրեք պատկերի նկարագրությունը այստեղ

Մի քանի կոպիտ թեստեր.

(41 մեգապիքսել, [7152x5368]) պատկերի փոխակերպում մոխրագույն մասշտաբի երկմիջուկային 2,1 ԳՀց սարքի վրա

  • GetPixel/SetPixel - Single Core - 131 վրկ.
  • LockBits - Single Core - 4,5 վրկ.
  • LockBits - Dual Core - 3 վրկ.
01.02.2014
  • Շատ շնորհակալ եմ ձեր պատասխանի համար։ Դա հենց այն է, ինչ ես վերջապես արեցի: Ես հենց նոր տեսա ձեր հաղորդագրությունը, այնպես որ ես արդեն գտել եմ լուծումը ինքնուրույն, բայց ժամանակ չունեի ավելի վաղ հրապարակելու: Կրկին շնորհակալություն ! 01.02.2014
  • Ես հենց նոր գտա այս պատասխանը. Այն հիանալի աշխատում է իմ MPI.Net հավելվածում: 26.11.2015
  • ինչպես անել նույնը android-ում: 25.04.2018

  • 2

    Մեկ այլ լուծում կլինի ժամանակավոր կոնտեյների ստեղծումը Bitmap-ի մասին տեղեկություններով, ինչպիսիք են լայնությունը, բարձրությունը, քայլը, բուֆերը և պիքսելային ձևաչափը: Երբ դուք պետք է զուգահեռ մուտք գործեք Bitmap, պարզապես ստեղծեք այն՝ հիմնվելով ժամանակավոր կոնտեյների տեղեկատվության վրա:

    Դրա համար մեզ անհրաժեշտ է ընդլայնման մեթոդ՝ Bitmap-ի բուֆերն ու քայլը ստանալու համար:

    public static Tuple<IntPtr, int> ToBufferAndStride(this Bitmap bitmap)
    {
        BitmapData bitmapData = null;
    
        try
        {
            bitmapData = bitmap.LockBits(new Rectangle(0, 0, bitmap.Width, bitmap.Height), 
                ImageLockMode.ReadOnly, bitmap.PixelFormat);
    
            return new Tuple<IntPtr, int>(bitmapData.Scan0, bitmapData.Stride);
        }
        finally
        {
            if (bitmapData != null)
                bitmap.UnlockBits(bitmapData);
        }
    }
    

    Այս երկարացման մեթոդը կօգտագործվի ժամանակավոր կոնտեյների ներսում.

    public class BitmapContainer
    {
        public PixelFormat Format { get; }
    
        public int Width { get; }
    
        public int Height { get; }
    
        public IntPtr Buffer { get; }
    
        public int Stride { get; set; }
    
        public BitmapContainer(Bitmap bitmap)
        {
            if (bitmap == null)
                throw new ArgumentNullException(nameof(bitmap));
    
            Format = bitmap.PixelFormat;
            Width = bitmap.Width;
            Height = bitmap.Height;
    
            var bufferAndStride = bitmap.ToBufferAndStride();
            Buffer = bufferAndStride.Item1;
            Stride = bufferAndStride.Item2;
        }
    
        public Bitmap ToBitmap()
        {
            return new Bitmap(Width, Height, Stride, Format, Buffer);
        }
    }
    

    Այժմ դուք կարող եք օգտագործել BitmapContainer-ը զուգահեռաբար կատարվող մեթոդում.

    BitmapContainer container = new BitmapContainer(bitmap);
    
    Parallel.For(0, 10, i =>
    {
        Bitmap parallelBitmap = container.ToBitmap();
        // ...
    });
    
    14.10.2018
  • Սա անվտանգ է: Ես դրա հետ կապված դեռ խնդիրներ չեմ տեսնում, և այն հիանալի է աշխատում: Բայց... ԻՆՉՈ՞ւ սա լուծում չէ բոլորի համար անընդհատ: 08.02.2021
  • Նոր նյութեր

    Օգտագործելով Fetch Vs Axios.Js-ը՝ HTTP հարցումներ կատարելու համար
    JavaScript-ը կարող է ցանցային հարցումներ ուղարկել սերվեր և բեռնել նոր տեղեկատվություն, երբ դա անհրաժեշտ լինի: Օրինակ, մենք կարող ենք օգտագործել ցանցային հարցումը պատվեր ներկայացնելու,..

    Տիրապետել հանգստության արվեստին. մշակողի ուղեցույց՝ ճնշման տակ ծաղկելու համար
    Տիրապետել հանգստության արվեստին. մշակողի ուղեցույց՝ ճնշման տակ ծաղկելու համար Ինչպե՞ս հանգստացնել ձեր միտքը և աշխատեցնել ձեր պրոցեսորը: Ինչպես մնալ հանգիստ և զարգանալ ճնշման տակ...

    Մեքենայի ուսուցում բանկային և ֆինանսների ոլորտում
    Բարդ, խելացի անվտանգության համակարգերը և հաճախորդների սպասարկման պարզեցված ծառայությունները բիզնեսի հաջողության բանալին են: Ֆինանսական հաստատությունները, մասնավորապես, պետք է առաջ մնան կորի..

    Ես AI-ին հարցրի կյանքի իմաստը, այն ինչ ասում էր, ցնցող էր:
    Այն պահից ի վեր, երբ ես իմացա Արհեստական ​​ինտելեկտի մասին, ես հիացած էի այն բանով, թե ինչպես է այն կարողանում հասկանալ մարդկային նորմալ տեքստը, և այն կարող է առաջացնել իր սեփական արձագանքը դրա..

    Ինչպես սովորել կոդավորումը Python-ում վագրի պես:
    Սովորելու համար ծրագրավորման նոր լեզու ընտրելը բարդ է: Անկախ նրանից, թե դուք սկսնակ եք, թե առաջադեմ, դա օգնում է իմանալ, թե ինչ թեմաներ պետք է սովորել: Ծրագրավորման լեզվի հիմունքները, դրա..

    C++-ի օրական բիթ(ե) | Ամենաերկար պալինդրոմային ենթաշարը
    C++ #198-ի ամենօրյա բիթ(ե), Ընդհանուր հարցազրույցի խնդիր. Ամենաերկար պալինդրոմային ենթատող: Այսօր մենք կանդրադառնանք հարցազրույցի ընդհանուր խնդրին. Ամենաերկար palindromic substring...

    Kydavra ICAReducer՝ ձեր տվյալների ծավալայինությունը նվազեցնելու համար
    Ի՞նչ է ICAReducer-ը: ICAReducer-ն աշխատում է հետևյալ կերպ. այն նվազեցնում է նրանց միջև բարձր փոխկապակցված հատկանիշները մինչև մեկ սյունակ: Բավականին նման է PCAreducer-ին, չնայած այն..