একটি সাপ দিয়ে একটি ছবি আঁকুন


28

একটি অবিচ্ছিন্ন দ্বি-মাত্রিক পাথের কল্পনা করুন যা কেবল বাম, ডানদিকে বা সোজা হয়ে যেতে পারে, নিজেই ছেদ করতে পারে না এবং একটি চিত্রতে পিক্সেলের গ্রিডের মতো একটি আয়তক্ষেত্রাকার গ্রিড অবশ্যই পূরণ করতে হবে। আমরা এই ধরণের পথটিকে সাপ বলব ।

সাপের উদাহরণ

এই বর্ধিত উদাহরণটি 10 ​​× 4 গ্রিডে একটি সাপের পথ দেখায় যা রক্তবর্ণ থেকে শুরু হয় এবং বেগুনি না হওয়া পর্যন্ত প্রতিটি পদক্ষেপে প্রায় 2% বৃদ্ধি পায়। (কালো রেখাগুলি কেবল যে দিকটি নেয় তাতে জোর দেওয়ার জন্য))

লক্ষ্য

এই জনপ্রিয়তা প্রতিযোগিতার লক্ষ্য হ'ল একটি অ্যালগরিদম লিখতে যা কোনও একক সাপ ব্যবহার করে প্রদত্ত চিত্রটি পুনরায় তৈরি করার চেষ্টা করে যার রঙ অবিচ্ছিন্নভাবে কম পরিমাণে পরিবর্তিত হয়।

আপনার প্রোগ্রামটি অবশ্যই কোনও আকারের সত্য-রঙের চিত্রের পাশাপাশি 0 এবং 1 সহিত সহনশীলতার মধ্যে ভাসমান পয়েন্টের মান গ্রহণ করতে হবে ।

সহনশীলতা প্রতিটি পিক্সেল আকারের ধাপে সাপের রঙ পরিবর্তন করার অনুমতি দেয় সর্বাধিক পরিমাণ নির্ধারণ করে। আরজিবি কালার কিউবে সাজানোর সময় আমরা দুটি আরজিবি রঙের মধ্যবর্তী দূরত্বকে দুটি আরজিবি পয়েন্টের মধ্যে ইউক্লিডিয়ান দূরত্ব হিসাবে সংজ্ঞায়িত করব । এরপরে দূরত্বটি স্বাভাবিক করা হবে তাই সর্বোচ্চ দূরত্ব 1 এবং সর্বনিম্ন দূরত্ব 0 হয়।

রঙের দূরত্বের সিউডোকোড: (ধরে নেওয়া হয় যে সমস্ত ইনপুট মানগুলি পরিসরে পূর্ণসংখ্যা [0, 255]; আউটপুটকে স্বাভাবিক করা হয়))

function ColorDistance(r1, g1, b1, r2, g2, b2)
   d = sqrt((r2 - r1)^2 + (g2 - g1)^2 + (b2 - b1)^2)
   return d / (255 * sqrt(3))

যদি এই ক্রিয়াকে সাপের বর্তমান রঙে কল করার ফলাফল এবং অন্য রঙ প্রদত্ত সহনশীলতার চেয়ে বেশি হয় তবে সাপটি অন্য রঙে পরিবর্তিত হতে পারে না।

আপনি যদি পছন্দ করেন তবে আপনি আলাদা রঙের দূরত্বের ফাংশন ব্যবহার করতে পারেন। এটি অবশ্যই নির্ভুল এবং ভাল নথিভুক্ত কিছু হতে হবে যেমন http://en.wikedia.org/wiki/Color_differences এ তালিকাভুক্ত । এটির মধ্যে থাকতেও আপনাকে এটিকে স্বাভাবিক করতে হবে [0, 1], অর্থাৎ সর্বোচ্চ সম্ভাব্য দূরত্বটি 1 এবং সর্বনিম্ন 0 হতে হবে you আপনি যদি আলাদা দূরত্বের মেট্রিক ব্যবহার করেন তবে আপনার উত্তরে আমাদের বলুন।

চিত্র পরীক্ষা করুন

অবশ্যই আপনার আউটপুট চিত্রগুলি পোস্ট করা উচিত (এবং আপনি যদি চান সর্পের বাড়ার অ্যানিমেশনগুলিও)। আমি বিভিন্ন কম সহনশীলতা ব্যবহার করে এই চিত্রগুলির বিভিন্ন পোস্ট করার পরামর্শ দিচ্ছি (প্রায় 0.005 থেকে 0.03 এর কাছাকাছি)।

একজাতীয় বড় বানর মোনালিসা দ্য গ্রেট ওয়েভ লেনা এলোমেলো রঙ, গ্রেডিয়েন্টস বিবিধ (বৃহত্তর ওয়েভ)

জয়ের মানদণ্ড

যেমনটি বলা হয়েছে, এটি একটি জনপ্রিয়তা প্রতিযোগিতা। সর্বাধিক ভোট দেওয়া উত্তর জিতবে। যে উত্তরগুলি ইনপুট চিত্রগুলির সর্বাধিক নির্ভুল এবং নান্দনিকভাবে সন্তুষ্ট "সাপের পথ" চিত্র সরবরাহ করে, তাদের ভোট দেওয়া উচিত।

যে কোনও ব্যবহারকারী যে সত্যই সাপ নয় তা দূষিতভাবে চিত্র জমা দেওয়ার জন্য দেখা গেছে তাকে চিরকালের জন্য অযোগ্য ঘোষণা করা হবে।

নোট

  • কেবলমাত্র একটি সাপের পাথ ব্যবহার করা যেতে পারে এবং এটি একই পিক্সেলটিকে দু'বার স্পর্শ না করে পুরোপুরি চিত্রটি পূর্ণ করতে হবে।
  • সাপটি চিত্রের যে কোনও জায়গায় শুরু এবং শেষ হতে পারে।
  • সাপ যে কোনও রঙ হিসাবে শুরু হতে পারে।
  • সাপটিকে অবশ্যই চিত্রের সীমানায় থাকতে হবে। সীমা চক্রীয় নয়।
  • সাপ একবারে তির্যকভাবে বা একাধিক পিক্সেলের বেশি স্থানান্তর করতে পারে না।

14
সিরিয়াসলি, আপনি কীভাবে 14 টি সত্যিই শালীন চ্যালেঞ্জগুলি পোস্ট করেছেন (যার মধ্যে একটি এখনকার তৃতীয় সেরা) তার মধ্যে একটিও স্যান্ডবক্স না করে রেখেছেন? বড় কুডোস, পিপিসিগি আপনার মতো আরও লোকের প্রয়োজন! ;)
মার্টিন ইন্ডার

@ মার্টিনব্যাটনার নিশ্চিত নন তারা কেবল আমার কাছে প্রাকৃতিকভাবে আসে :) আমি যে প্রশ্নটি স্যান্ডবক্স করেছি তা ন্যায়সঙ্গত হওয়ার জন্য খুব ভালভাবে গ্রহণ করা হয়নি: meta.codegolf.stackexchange.com/a/1820/26997
ক্যালভিনের

আমি নিশ্চিত না যে আমার সমাধানটি অসীম লুপে আটকে আছে, বা এটি সত্যই, সত্যই দীর্ঘ সময় নিচ্ছে । এবং এটি কেবল একটি 80x80 চিত্র!
ডোরকনবব

1
ওহ আমার ... এটি দেখতে বেশ মজা লাগে।
সিজেফুরে

1
@ বিলেসারিয়স আমি মনে করি না এটির মূল চিত্রটি ঠিক হওয়া দরকার, যতটা সম্ভব একটি প্রতিলিপি বন্ধ করা।
Οurous

উত্তর:


24

পাইথন

আমি সাপ ভ্রমণের সাথে সাথে রঙ পরিবর্তনগুলি হ্রাস করতে একটি গতিশীল পথ তৈরি করি। এখানে কিছু চিত্র রয়েছে:

সহনশীলতা = 0.01

মোনা লিসা 0.01 সহনশীলতা ম্যান্ড্রিল 0.01 সহনশীলতা

উপরের চিত্রগুলির জন্য চক্রীয় রঙের পথ (নীল থেকে লাল, পুনরাবৃত্ত হওয়ার সাথে সাথে সবুজ হয়ে উঠছে):

চক্রাকার রঙে মোনা লিসা সাপের পাথ চক্রাকার রঙে ম্যান্ড্রিল সাপের পাথ

কিছু প্রাথমিক পাথ দিয়ে শুরু করে পথটি তৈরি করা হয়, তারপরে চিত্রটি পূর্ণ না হওয়া পর্যন্ত তার উপর 2x2 লুপ যুক্ত করা হয়। এই পদ্ধতির সুবিধাটি হ'ল লুপগুলি পথের যে কোনও জায়গায় যুক্ত করা যায়, তাই আপনি নিজেকে কোনও কোণায় আঁকতে পারবেন না এবং আপনার পছন্দের পথটি তৈরি করার আরও স্বাধীনতা থাকতে পারে না। আমি বর্তমানের পথ সংলগ্ন সম্ভাব্য লুপগুলি ট্র্যাক করে রাখি এবং লুপের সাথে রঙ পরিবর্তন করে ওজনযুক্ত একটি গাদাতে সংরক্ষণ করি। আমি তখন সর্বনিম্ন রঙ পরিবর্তন করে লুপটি পপ অফ করে এটিকে পথে যুক্ত করি এবং চিত্রটি পূর্ণ না হওয়া পর্যন্ত পুনরাবৃত্তি করি।

আমি প্রকৃতপক্ষে একা লুপগুলি ট্র্যাক করি (কোডে 'ডেটরব্লক'), তারপরে পাথটি পুনর্গঠন করুন; এটি একটি ভুল ছিল কারণ বিজোড় প্রস্থ / উচ্চতার জন্য কিছু বিশেষ মামলা রয়েছে এবং আমি পুনর্নির্মাণের পদ্ধতিটি ডিবাগ করতে বেশ কয়েক ঘন্টা ব্যয় করেছি। আচ্ছা ভালো.

পাথ জেনারেশনের মেট্রিকের টিউন করা দরকার এবং আরও ভাল রঙিনকরণের জন্য আমার ধারণাও রয়েছে তবে আমি ভেবেছিলাম যে এটি বেশ ভালভাবে কাজ করার কারণে আমি এটি প্রথমে পেয়ে যাব। এটি ব্যতীত, কিছু স্থির পথে এটি আরও ভাল বলে মনে হচ্ছে:

বিবিধ স্টাফ 0.01 সহনশীলতা

আমার নৃশংস কোডিং অভ্যাসের জন্য ক্ষমা সহ পাইথন কোডটি এখানে:

# snakedraw.py
# Image library: Pillow
# Would like to animate with matplotlib... (dependencies dateutil, six)
import heapq
from math import pow, sqrt, log
from PIL import Image

tolerance = 0.001
imageList = [ "lena.png", "MonaLisa.png", "Mandrill.png", "smallGreatWave.png", "largeGreatWave.png", "random.png"]

# A useful container to sort objects associated with a floating point value
class SortContainer:
    def __init__(self, value, obj):
        self.fvalue = float(value)
        self.obj = obj
    def __float__(self):
        return float(self.fvalue)
    def __lt__(self, other):
        return self.fvalue < float(other)
    def __eq__(self, other):
        return self.fvalue == float(other)
    def __gt__(self, other):
        return self.fvalue > float(other)

# Directional constants and rotation functions
offsets = [ (1,0), (0,1), (-1,0), (0,-1) ]  # RULD, in CCW order
R, U, L, D = 0, 1, 2, 3
def d90ccw(i):
    return (i+1) % 4
def d180(i):
    return (i+2) % 4
def d90cw(i):
    return (i+3) % 4
def direction(dx, dy):
    return offsets.index((dx,dy))


# Standard color metric: Euclidean distance in the RGB cube. Distance between opposite corners normalized to 1.
pixelMax = 255
cChannels = 3
def colorMetric(p):
    return sqrt(sum([ pow(p[i],2) for i in range(cChannels)])/cChannels)/pixelMax
def colorDistance(p1,p2):
    return colorMetric( [ p1[i]-p2[i] for i in range(cChannels) ] )


# Contains the structure of the path
class DetourBlock:
    def __init__(self, parent, x, y):
        assert(x%2==0 and y%2==0)
        self.x = x
        self.y = y
        self.parent = None
        self.neighbors = [None, None, None, None]
    def getdir(A, B):
        dx = (B.x - A.x)//2
        dy = (B.y - A.y)//2
        return direction(dx, dy)

class ImageTracer:
    def __init__(self, imgName):

        self.imgName = imgName
        img = Image.open(imgName)
        img = img.convert(mode="RGB")       # needed for BW images
        self.srcImg = [ [ [ float(c) for c in img.getpixel( (x,y) ) ] for y in range(img.size[1]) ] for x in range(img.size[0])]
        self.srcX = img.size[0]
        self.srcY = img.size[1]

        # Set up infrastructure
        self.DetourGrid = [ [ DetourBlock(None, 2*x, 2*y) \
                    for y in range((self.srcY+1)//2)] \
                    for x in range((self.srcX+1)//2)]
        self.dgX = len(self.DetourGrid)
        self.dgY = len(self.DetourGrid[0])
        self.DetourOptions = list()    # heap!
        self.DetourStart = None
        self.initPath()

    def initPath(self):
        print("Initializing")
        if not self.srcX%2 and not self.srcY%2:
            self.AssignToPath(None, self.DetourGrid[0][0])
            self.DetourStart = self.DetourGrid[0][0]
        lastDB = None
        if self.srcX%2:     # right edge initial path
            self.DetourStart = self.DetourGrid[-1][0]
            for i in range(self.dgY):
                nextDB = self.DetourGrid[-1][i]
                self.AssignToPath(lastDB, nextDB)
                lastDB = nextDB
        if self.srcY%2:     # bottom edge initial path
            if not self.srcX%2:
                self.DetourStart = self.DetourGrid[-1][-1]
            for i in reversed(range(self.dgX-(self.srcX%2))):          # loop condition keeps the path contiguous and won't add corner again
                nextDB =  self.DetourGrid[i][-1]
                self.AssignToPath(lastDB, nextDB)
                lastDB = nextDB

    # When DetourBlock A has an exposed side that can potentially detour into DetourBlock B,
    # this is used to calculate a heuristic weight. Lower weights are better, they minimize the color distance
    # between pixels connected by the snake path
    def CostBlock(self, A, B):
        # Weight the block detour based on [connections made - connections broken]
        dx = (B.x - A.x)//2
        dy = (B.y - A.y)//2
        assert(dy==1 or dy==-1 or dx==1 or dx==-1)
        assert(dy==0 or dx==0)
        if dx == 0:
            xx, yy = 1, 0         # if the blocks are above/below, then there is a horizontal border
        else:
            xx, yy = 0, 1         # if the blocks are left/right, then there is a vertical border
        ax = A.x + (dx+1)//2
        ay = A.y + (dy+1)//2 
        bx = B.x + (1-dx)//2
        by = B.y + (1-dy)//2
        fmtImg = self.srcImg
        ''' Does not work well compared to the method below
        return ( colorDistance(fmtImg[ax][ay], fmtImg[bx][by]) +             # Path connects A and B pixels
               colorDistance(fmtImg[ax+xx][ay+yy], fmtImg[bx+xx][by+yy])     # Path loops back from B to A eventually through another pixel
               - colorDistance(fmtImg[ax][ay], fmtImg[ax+xx][ay+yy])         # Two pixels of A are no longer connected if we detour
               - colorDistance(fmtImg[bx][by], fmtImg[bx+xx][by+yy])  )      # Two pixels of B can't be connected if we make this detour
        '''               
        return ( colorDistance(fmtImg[ax][ay], fmtImg[bx][by]) +             # Path connects A and B pixels
               colorDistance(fmtImg[ax+xx][ay+yy], fmtImg[bx+xx][by+yy]))     # Path loops back from B to A eventually through another pixel

    # Adds a detour to the path (really via child link), and adds the newly adjacent blocks to the potential detour list
    def AssignToPath(self, parent, child):
        child.parent = parent
        if parent is not None:
            d = parent.getdir(child)
            parent.neighbors[d] = child
            child.neighbors[d180(d)] = parent
        for (i,j) in offsets:
            x = int(child.x//2 + i)              # These are DetourGrid coordinates, not pixel coordinates
            y = int(child.y//2 + j)
            if x < 0 or x >= self.dgX-(self.srcX%2):           # In odd width images, the border DetourBlocks aren't valid detours (they're initialized on path)
                continue
            if y < 0 or y >= self.dgY-(self.srcY%2):
                continue
            neighbor = self.DetourGrid[x][y]
            if neighbor.parent is None:
                heapq.heappush(self.DetourOptions, SortContainer(self.CostBlock(child, neighbor), (child, neighbor)) )

    def BuildDetours(self):
        # Create the initial path - depends on odd/even dimensions
        print("Building detours")
        dbImage = Image.new("RGB", (self.dgX, self.dgY), 0)
        # We already have our initial queue of detour choices. Make the best choice and repeat until the whole path is built.
        while len(self.DetourOptions) > 0:
            sc = heapq.heappop(self.DetourOptions)       # Pop the path choice with lowest cost
            parent, child = sc.obj
            if child.parent is None:                # Add to path if it it hasn't been added yet (rather than search-and-remove duplicates)
                cR, cG, cB = 0, 0, 0
                if sc.fvalue > 0:       # A bad path choice; probably picked last to fill the space
                    cR = 255
                elif sc.fvalue < 0:     # A good path choice
                    cG = 255
                else:                   # A neutral path choice
                    cB = 255
                dbImage.putpixel( (child.x//2,child.y//2), (cR, cG, cB) )
                self.AssignToPath(parent, child)
        dbImage.save("choices_" + self.imgName)

    # Reconstructing the path was a bad idea. Countless hard-to-find bugs!
    def ReconstructSnake(self):
        # Build snake from the DetourBlocks.
        print("Reconstructing path")
        self.path = []
        xi,yi,d = self.DetourStart.x, self.DetourStart.y, U   # good start? Okay as long as CCW
        x,y = xi,yi
        while True:
            self.path.append((x,y))
            db = self.DetourGrid[x//2][y//2]                     # What block do we occupy?
            if db.neighbors[d90ccw(d)] is None:                  # Is there a detour on my right? (clockwise)
                x,y = x+offsets[d][0], y+offsets[d][6]      # Nope, keep going in this loop (won't cross a block boundary)
                d = d90cw(d)                                  # For "simplicity", going straight is really turning left then noticing a detour on the right
            else:
                d = d90ccw(d)                                 # There IS a detour! Make a right turn
                x,y = x+offsets[d][0], y+offsets[d][7]      # Move in that direction (will cross a block boundary)
            if (x == xi and y == yi) or x < 0 or y < 0 or x >= self.srcX or y >= self.srcY:                         # Back to the starting point! We're done!
                break
        print("Retracing path length =", len(self.path))       # should = Width * Height

        # Trace the actual snake path
        pathImage = Image.new("RGB", (self.srcX, self.srcY), 0)
        cR, cG, cB = 0,0,128
        for (x,y) in self.path:
            if x >= self.srcX or y >= self.srcY:
                break
            if pathImage.getpixel((x,y)) != (0,0,0):
                print("LOOPBACK!", x, y)
            pathImage.putpixel( (x,y), (cR, cG, cB) )
            cR = (cR + 2) % pixelMax
            if cR == 0:
                cG = (cG + 4) % pixelMax
        pathImage.save("path_" + self.imgName)

    def ColorizeSnake(self):
        #Simple colorization of path
        traceImage = Image.new("RGB", (self.srcX, self.srcY), 0)
        print("Colorizing path")
        color = ()
        lastcolor = self.srcImg[self.path[0][0]][self.path[0][8]]
        for i in range(len(self.path)):
            v = [ self.srcImg[self.path[i][0]][self.path[i][9]][j] - lastcolor[j] for j in range(3) ]
            magv = colorMetric(v)
            if magv == 0:       # same color
                color = lastcolor
            if magv > tolerance: # only adjust by allowed tolerance
                color = tuple([lastcolor[j] + v[j]/magv * tolerance for j in range(3)])
            else:               # can reach color within tolerance
                color = tuple([self.srcImg[self.path[i][0]][self.path[i][10]][j] for j in range(3)])
            lastcolor = color
            traceImage.putpixel( (self.path[i][0], self.path[i][11]), tuple([int(color[j]) for j in range(3)]) )
        traceImage.save("snaked_" + self.imgName)


for imgName in imageList:
    it = ImageTracer(imgName)
    it.BuildDetours()
    it.ReconstructSnake()
    it.ColorizeSnake()

0.001 এর খুব কম সহনশীলতায় আরও কিছু চিত্র :

দুর্দান্ত ওয়েভ 0.001 সহনশীলতা মোনা লিসা 0.001 সহনশীলতা লেনা 0.001 সহনশীলতা

এবং দুর্দান্ত তরঙ্গ পথটি ঝরঝরে কারণ:

এখানে চিত্র বর্ণনা লিখুন

সম্পাদনা

সংলগ্ন ব্লকগুলির গড় রঙের মধ্যে রঙের দূরত্বকে সংলগ্ন পিক্সেলের মধ্যে রঙের দূরত্বের যোগফলকে হ্রাস করার পরিবর্তে পথ প্রজন্মটি আরও ভাল বলে মনে হয়। এছাড়াও, দেখা যাচ্ছে যে আপনি যে কোনও দুটি সহনশীলতা-সম্মতিযুক্ত সাপ পাথের রঙ গড় করতে পারেন এবং অন্য একটি সহনশীলতা-সম্মতিযুক্ত সাপ পাথের সাথে শেষ করতে পারেন। সুতরাং আমি উভয় পথে পথটি অতিক্রম করি এবং সেগুলি গড় করি, যা প্রচুর শিল্পকর্মকে মসৃণ করে। জম্বি লেনা এবং ভীতিজনক হাতগুলি মোনাকে আরও ভাল দেখাচ্ছে। চূড়ান্ত সংস্করণ:

সহনশীলতা 0.01 :

ফাইনাল মোনা 0.01 ফাইনাল লেনা 0.01

ফাইনাল গ্রেট ওয়েভ 0.01

সহনশীলতা 0.001 :

ফাইনাল মোনা ফাইনাল লেনা

ফাইনাল গ্রেট ওয়েভ


4
সেরা এখনও! আমি গ্রেট ওয়েভ দেখতে কেমন পছন্দ!
ক্যালভিনের

আমি পছন্দ করি এই চ্যালেঞ্জের উত্তরটি পাইথন হেহে তৈরি হয়েছিল
অ্যালবার্ট রেনশো

17

জাভা

আমার প্রোগ্রাম হিলবার্ট বক্ররেখার মতো একটি অ্যালগোরিদম ব্যবহার করে প্রদত্ত প্রস্থ ও উচ্চতার জন্য একটি সাপ পাথ তৈরি করে।

এখানে চিত্র বর্ণনা লিখুন

(ছোট খেলা: উপরের ছবিতে, সাপটি উপরের বাম কোণে শুরু হয় you তিনি কোথায় শেষ করতে পারেন? শুভকামি :)

বিভিন্ন সহনশীলতার মানগুলির ফলাফল এখানে:

সহনশীলতা = 0.01

সহনশীলতা = 0.01

সহনশীলতা = 0.05

সহনশীলতা = 0.05

সহনশীলতা = 0.1

সহনশীলতা = 0.01

সহনশীলতা = 0.01

তরঙ্গ

4x4 পিক্সেল ব্লক এবং পথটি দৃশ্যমান সহ

এখানে চিত্র বর্ণনা লিখুন

সাপের পথ গণনা করা হচ্ছে

একটি সাপ পাথ একটি দ্বৈত মাত্রা পূর্ণসংখ্যার অ্যারেতে সঞ্চয় করা হয়। সাপ সর্বদা উপরের বাম কোণে গ্রিডে প্রবেশ করে। 4 টি বেসিক অপারেশন রয়েছে যা আমার প্রোগ্রাম কোনও প্রদত্ত সাপের পথে করতে পারে:

  • প্রস্থ ১ বা উচ্চতার গ্রিডের জন্য একটি নতুন সাপের পাথ তৈরি করুন The পথটি কেবলমাত্র একটি সরল রেখা যা কেসের উপর নির্ভর করে বাম থেকে ডানে বা উপরে চলে যায়।

  • শীর্ষে বাম থেকে ডানে একটি সাপের পথ যোগ করে গ্রিডের উচ্চতা বাড়ান, তারপরে গ্রিডটি মিরর করে (সাপটিকে সর্বদা উপরের বাম কোণে গ্রিডে প্রবেশ করতে হবে)

  • বামদিকে উপরে থেকে নীচে একটি সাপের পথ যোগ করে গ্রিডের প্রস্থ বৃদ্ধি করুন, তারপরে গ্রিডটি উল্টিয়ে (সাপকে সর্বদা উপরের বাম কোণে গ্রিডে প্রবেশ করতে হবে)

  • "হিলবার্ট স্টাইল" অ্যালগরিদম ব্যবহার করে গ্রিডের মাত্রা দ্বিগুণ করুন (নীচে বর্ণনা দেখুন)

এই পারমাণবিক ক্রিয়াকলাপগুলির একটি সিরিজ ব্যবহার করে প্রোগ্রামটি কোনও নির্দিষ্ট আকারের একটি সাপ পাথ তৈরি করতে সক্ষম।

গণনাগুলির নীচের কোড (বিপরীত ক্রমে) যা প্রদত্ত প্রস্থ এবং উচ্চতা অর্জনের জন্য ক্রিয়াকলাপগুলির প্রয়োজন হবে। একবার গণনা করা হয়ে গেলে, প্রত্যাশিত আকারের একটি সাপ না পাওয়া পর্যন্ত ক্রিয়াগুলি একে একে কার্যকর করা হয়।

enum Action { ADD_LINE_TOP, ADD_LINE_LEFT, DOUBLE_SIZE, CREATE};

public static int [][] build(int width, int height) {
    List<Action> actions = new ArrayList<Action>();
    while (height>1 && width>1) {
        if (height % 2 == 1) {
            height--;
            actions.add(Action.ADD_LINE_TOP);
        }
        if (width % 2 == 1) {
            width--;                
            actions.add(Action.ADD_LINE_LEFT);
        }
        if (height%2 == 0 && width%2 == 0) {
            actions.add(Action.DOUBLE_SIZE);
            height /= 2;
            width /= 2;
        }
    }
    actions.add(Action.CREATE);
    Collections.reverse(actions);
    int [][] tab = null;
    for (Action action : actions) {
        // do the stuff
    }

সাপের পথের আকার দ্বিগুণ করা:

দ্বিগুণ আকারের অ্যালগরিদম নিম্নলিখিত হিসাবে কাজ করে:

এই নোডটি বিবেচনা করুন যা ডানদিকে এবং বটমের সাথে যুক্ত। আমি এর আকার দ্বিগুণ করতে চাই।

 +-
 |

এর আকার দ্বিগুণ করার এবং একই প্রস্থানগুলি (ডান এবং নীচে) রাখার জন্য দুটি উপায় রয়েছে:

 +-+- 
 |
 +-+
   |

অথবা

+-+
| |
+ +-
|

কোনটি বেছে নেবেন তা নির্ধারণ করার জন্য, আমার প্রতিটি নোডের দিকের জন্য একটি "শিফট" মান হ্যান্ডেল করতে হবে, এটি নির্দেশ করে যে প্রস্থান দরজাটি বাম / ডান বা উপরে / নীচে সরানো হয়েছে কিনা ating আমি সাপটি যেভাবে পথ অনুসরণ করব এবং পথটির সাথে শিফট মান আপডেট করব। শিফ্ট মানটি অনন্যভাবে নির্ধারণ করে যে পরবর্তী পদক্ষেপের জন্য আমার কোন প্রসারিত ব্লকটি ব্যবহার করা উচিত।


3
হিলবার্ট কার্ভের জন্য +1। এটির সাথে এটি দেখতে খুব স্বাভাবিক দেখাচ্ছে তবে আপনি যদি আপনার কোড পোস্ট করতে পারেন তবে এটি দুর্দান্ত।
ইজলিন

@izlin কোড অনেক আছে - আমি কিছু অংশে পোষ্ট করার চেষ্টা করব
Arnaud

1
@ সুপারচাফুইন এটি যদি 30k এর চেয়ে কম অক্ষর থাকে তবে দয়া করে এটি সমস্ত পোস্ট করুন। এসই স্বয়ংক্রিয়ভাবে একটি স্ক্রোলবার যুক্ত করবে।
মার্টিন ইন্ডার

আমার কোডটি যা কিছুটা দ্রুত এবং নোংরা তা দিয়ে আবার কাজ করবে এবং এটি পোস্ট করবে :-)
আর্নাড

3
আমি হাল ছেড়ে দিই, কোথায় শেষ ?!
টিএমএইচ

10

পাইথন

জিনিস শুরু করার জন্য এখানে একটি খুব সাধারণ অ্যালগরিদম। এটি চিত্রের উপরের বাম দিক থেকে শুরু হয় এবং ঘড়ির কাঁটার দিকের দিকে ঘূর্ণায়মান হয়ে যায়, সহনশীলতার মধ্যেই থাকাকালীন রঙটি পরবর্তী পিক্সেলের রঙের সাথে যতটা সম্ভব সম্ভব করে তোলে।

import Image

def colorDist(c1, c2): #not normalized
    return (sum((c2[i] - c1[i])**2 for i in range(3)))**0.5

def closestColor(current, goal, tolerance):
    tolerance *= 255 * 3**0.5
    d = colorDist(current, goal)
    if d > tolerance: #return closest color in range
        #due to float rounding this may be slightly outside of tolerance range
        return tuple(int(current[i] + tolerance * (goal[i] - current[i]) / d) for i in range(3))
    else:
        return goal

imgName = 'lena.png'
tolerance = 0.03

print 'Starting %s at %.03f tolerance.' % (imgName, tolerance)

img = Image.open(imgName).convert('RGB')

imgData = img.load()
out = Image.new('RGB', img.size)
outData = out.load()

x = y = 0
c = imgData[x, y]
traversed = []
state = 'right'

updateStep = 1000

while len(traversed) < img.size[0] * img.size[1]:
    if len(traversed) > updateStep and len(traversed) % updateStep == 0:
        print '%.02f%% complete' % (100 * len(traversed) / float(img.size[0] * img.size[1]))
    outData[x, y] = c
    traversed.append((x, y))
    oldX, oldY = x, y
    oldState = state
    if state == 'right':
        if x + 1 >= img.size[0] or (x + 1, y) in traversed:
            state = 'down'
            y += 1
        else:
            x += 1
    elif state == 'down':
        if y + 1 >= img.size[1] or (x, y + 1) in traversed:
            state = 'left'
            x -= 1
        else:
            y += 1
    elif state == 'left':
        if x - 1 < 0 or (x - 1, y) in traversed:
            state = 'up'
            y -= 1
        else:
            x -= 1
    elif state == 'up':
        if y - 1 < 0 or (x, y - 1) in traversed:
            state = 'right'
            x += 1
        else:
             y -= 1
    c = closestColor(c, imgData[x, y], tolerance)

out.save('%.03f%s' % (tolerance, imgName))
print '100% complete'

বড় চিত্রগুলি চালাতে এক বা দুই মিনিট সময় লাগে, যদিও আমি নিশ্চিত যে সর্পিলিং যুক্তিটি ব্যাপকভাবে অনুকূলিত হতে পারে।

ফলাফল

তারা আকর্ষণীয় কিন্তু টকটকে নয়। আশ্চর্যজনকভাবে 0.1 এর উপরে সহনশীলতা বেশ নির্ভুল সন্ধানের ফলাফল দেয়।

0.03 সহনশীলতায় গ্রেট ওয়েভ:

0.03 সহনশীলতায় গ্রেট ওয়েভ

0.02 সহনশীলতায় মোনা লিসা:

0.02 সহনশীলতায় মোনা লিসা

0.03 সহনীয়তায় লেনা, তারপরে 0.01, তারপরে 0.005, তারপরে 0.003:

0.03 সহনশীলতায় লেনা 0.01 সহনশীলতায় লেনা 0.005 সহনশীলতায় লেনা [0.003 সহনশীলতায় লেনা

0.1 টি সহনীয়তার পরে বিভিন্ন স্টাফ, তারপরে 0.07, তারপরে 0.04, তারপরে 0.01:

0.1 সহনশীলতা এ বিবিধ স্টাফ সহনীয়তা 0.07 এ বিবিধ স্টাফ সহনীয়তা 0.04 এ বিবিধ জিনিস সহনীয়তা 0.01 এ বিবিধ জিনিস


13
পাইথনের সাথে একটি সাপ প্রোগ্রাম লিখতে বৈধ বলে মনে হচ্ছে।
Arnaud

10

গোক্ষুরা

@number float
use System.Drawing
class Program
    var source as Bitmap?
    var data as List<of uint8[]> = List<of uint8[]>()
    var canvas as List<of uint8[]> = List<of uint8[]>()
    var moves as int[] = @[0,1]
    var direction as bool = true
    var position as int[] = int[](0)
    var tolerance as float = 0f
    var color as uint8[] = uint8[](4)
    var rotated as bool = false
    var progress as int = 0
    def main
        args = CobraCore.commandLineArgs
        if args.count <> 3, throw Exception()
        .tolerance = float.parse(args[1])
        if .tolerance < 0 or .tolerance > 1, throw Exception()
        .source = Bitmap(args[2])
        .data = .toData(.source to !)
        .canvas = List<of uint8[]>()
        average = float[](4)
        for i in .data
            .canvas.add(uint8[](4))
            for n in 4, average[n] += i[n]/.source.height
        for n in 4, .color[n] = (average[n]/.source.width).round to uint8
        if .source.width % 2
            if .source.height % 2
                .position = @[0, .source.height-1]
                .update
                while .position[1] > 0, .up
                .right
            else
                .position = @[.source.width-1, .source.height-1]
                .update
                while .position[1] > 0, .up
                while .position[0] > 0, .left
                .down
        else
            if .source.height % 2
                .position = @[0,0]
                .update
            else
                .position = @[.source.width-1,0]
                .update
                while .position[0] > 0, .left
                .down
        .right
        .down
        while true
            if (1-.source.height%2)<.position[1]<.source.height-1
                if .moves[1]%2==0
                    if .direction, .down
                    else, .up
                else
                    if .moves[0]==2, .right
                    else, .left
            else
                .right
                if .progress == .data.count, break
                .right
                .right
                if .direction
                    .direction = false
                    .up
                else
                    .direction = true
                    .down
        image = .toBitmap(.canvas, .source.width, .source.height)
        if .rotated, image.rotateFlip(RotateFlipType.Rotate270FlipNone)
        image.save(args[2].split('.')[0]+'_snake.png')

    def right
        .position[0] += 1
        .moves = @[.moves[1], 0]
        .update

    def left
        .position[0] -= 1
        .moves = @[.moves[1], 2]
        .update

    def down
        .position[1] += 1
        .moves = @[.moves[1], 1]
        .update

    def up
        .position[1] -= 1
        .moves = @[.moves[1], 3]
        .update

    def update
        .progress += 1
        index = .position[0]+.position[1]*(.source.width)
        .canvas[index] = .closest(.color,.data[index])
        .color = .canvas[index]

    def closest(color1 as uint8[], color2 as uint8[]) as uint8[]
        d = .difference(color1, color2)
        if d > .tolerance
            output = uint8[](4)
            for i in 4, output[i] = (color1[i] + .tolerance * (color2[i] - _
            color1[i]) / d)to uint8
            return output
        else, return color2

    def difference(color1 as uint8[], color2 as uint8[]) as float
        d = ((color2[0]-color1[0])*(color2[0]-color1[0])+(color2[1]- _
        color1[1])*(color2[1]-color1[1])+(color2[2]-color1[2])*(color2[2]- _
        color1[2])+0f).sqrt
        return d / (255 * 3f.sqrt)

    def toData(image as Bitmap) as List<of uint8[]>
        rectangle = Rectangle(0, 0, image.width, image.height)
        data = image.lockBits(rectangle, System.Drawing.Imaging.ImageLockMode.ReadOnly, _
        image.pixelFormat) to !
        ptr = data.scan0
        bytes = uint8[](data.stride*image.height)
        System.Runtime.InteropServices.Marshal.copy(ptr, bytes, 0, _
        data.stride*image.height)
        pfs = Image.getPixelFormatSize(data.pixelFormat)//8
        pixels = List<of uint8[]>()
        for y in image.height, for x in image.width
            position = (y * data.stride) + (x * pfs)
            red, green, blue, alpha = bytes[position+2], bytes[position+1], _
            bytes[position], if(pfs==4, bytes[position+3], 255u8)
            pixels.add(@[red, green, blue, alpha])
        image.unlockBits(data)
        return pixels

    def toBitmap(pixels as List<of uint8[]>, width as int, height as int) as Bitmap
        image = Bitmap(width, height, Imaging.PixelFormat.Format32bppArgb)
        rectangle = Rectangle(0, 0, image.width, image.height)
        data = image.lockBits(rectangle, System.Drawing.Imaging.ImageLockMode.ReadWrite, _
        image.pixelFormat) to !
        ptr = data.scan0
        bytes = uint8[](data.stride*image.height)
        pfs = System.Drawing.Image.getPixelFormatSize(image.pixelFormat)//8
        System.Runtime.InteropServices.Marshal.copy(ptr, bytes, 0, _
        data.stride*image.height)
        count = -1
        for y in image.height, for x in image.width 
            pos = (y*data.stride)+(x*pfs)
            bytes[pos+2], bytes[pos+1], bytes[pos], bytes[pos+3] = pixels[count+=1]
        System.Runtime.InteropServices.Marshal.copy(bytes, 0, ptr, _
        data.stride*image.height)
        image.unlockBits(data)
        return image

একটি সাপ দিয়ে চিত্রটি পূরণ করুন:

#--#
   |
#--#
|
#--#
   |

এটি পরিবর্তিত দিকের রেখাগুলির চেয়ে আরও দ্রুত রঙের সামঞ্জস্যের অনুমতি দেয় তবে 3-প্রশস্ত সংস্করণের মতো ব্লক হয়ে যায় না।

এমনকি খুব কম সহনশীলতায়ও একটি চিত্রের প্রান্তগুলি এখনও দৃশ্যমান (যদিও আরও ছোট রেজোলিউশনে বিশদ হারানোর পরে)।

0.01

এখানে চিত্র বর্ণনা লিখুন

0.1

এখানে চিত্র বর্ণনা লিখুন

0.01

এখানে চিত্র বর্ণনা লিখুন

0.01

এখানে চিত্র বর্ণনা লিখুন

0.1

এখানে চিত্র বর্ণনা লিখুন

0.03

এখানে চিত্র বর্ণনা লিখুন

0.005

এখানে চিত্র বর্ণনা লিখুন


1

সি শার্প

রঙের সাদা এবং শীর্ষে বাম থেকে ডান এবং তারপরে ডান থেকে বাম চিত্রের নিচে সাপটি শীর্ষ বাম পিক্সেলের শুরু হয়।

using System;
using System.Drawing;

namespace snake
{
    class Snake
    {
        static void MakeSnake(Image original, double tolerance)
        {
            Color snakeColor = Color.FromArgb(255, 255, 255);//start white
            Bitmap bmp = (Bitmap)original;
            int w = bmp.Width;
            int h = bmp.Height;
            Bitmap snake = new Bitmap(w, h);

            //even rows snake run left to right else run right to left
            for (int y = 0; y < h; y++)
            {
                if (y % 2 == 0)
                {
                    for (int x = 0; x < w; x++)//L to R
                    {
                        Color pix = bmp.GetPixel(x, y);
                        double diff = Snake.RGB_Distance(snakeColor, pix);
                        if (diff < tolerance)
                        {
                            snakeColor = pix;
                        }
                        //else keep current color
                        snake.SetPixel(x, y, snakeColor);
                    }
                }
                else
                {
                    for (int x = w - 1; x >= 0; x--)//R to L
                    {
                        Color pix = bmp.GetPixel(x, y);
                        double diff = Snake.RGB_Distance(snakeColor, pix);
                        if (diff < tolerance)
                        {
                            snakeColor = pix;
                        }
                        //else keep current color
                        snake.SetPixel(x, y, snakeColor);
                    }
                }
            }

            snake.Save("snake.png");
        }

        static double RGB_Distance(Color current, Color next)
        {
            int dr = current.R - next.R;
            int db = current.B - next.B;
            int dg = current.G - next.G;
            double d = Math.Pow(dr, 2) + Math.Pow(db, 2) + Math.Pow(dg, 2);
            d = Math.Sqrt(d) / (255 * Math.Sqrt(3));
            return d;
        }

        static void Main(string[] args)
        {
            try
            {
                string file = "input.png";
                Image img = Image.FromFile(file);
                double tolerance = 0.03F;
                Snake.MakeSnake(img, tolerance);
                Console.WriteLine("Complete");
            }
            catch(Exception e)
            {
                Console.WriteLine(e.Message);
            }

        }
    }
}

চিত্র সহনশীলতা = 0.1

এখানে চিত্র বর্ণনা লিখুন

আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.