Ejemplo n.º 1
0
def openPhotonFile(filename):
    global photonfile
    global dispimg
    global layerimg
    global previmg
    global layerNr
    # read file
    photonfile = PhotonFile(filename)
    photonfile.readFile()

    layerNr = 0  # reset this to 0 so we prevent crash if previous photonfile was navigated to layer above the last layer of new photonfile
    layerimg = photonfile.getBitmap(layerNr, layerForecolor, layerBackcolor)
    previmg[0] = photonfile.getPreviewBitmap(0)
    previmg[1] = photonfile.getPreviewBitmap(1)
    dispimg = layerimg
    refreshHeaderControls()
    refreshPreviewControls()
    refreshLayerControls()
Ejemplo n.º 2
0
def testcases():

    # Test cases
    # read / save photon file
    # read / save cbddlp file (should be same as photon file)

    # read / save properties for header/layers
    #

    print("Save All...")
    photon_filepath_org = '/home/nard/PhotonFile/test/bunny.photon'
    photonfile = PhotonFile()
    photonfile.load(photon_filepath_org)
    photon_dirpath_new = '/home/nard/PhotonFile/test/bunny.img'
    photonfile.layers.saveAll(photon_dirpath_new)
    print("...success.")

    return

    print("Test signatures...")
    photonfile = PhotonFile()
    photon_filepath_org = '/home/nard/PhotonFile/test/bunny.photon'
    photonfile.load(photon_filepath_org)
    assert (photonfile.signature() == 'ChituBox 1.4.0')
    print("...success.")

    print("Test read/write .cbddlp file...")
    filepath = '/home/nard/PhotonFile/test/bunny.cbddlp'
    filepath_new = '/home/nard/PhotonFile/test/bunny2.cbddlp'
    org_filesize = os.path.getsize(filepath)
    photonfile = PhotonFile(filepath)
    photonfile.load()
    photonfile.save(filepath_new)
    new_filesize = os.path.getsize(filepath_new)
    assert new_filesize == org_filesize
    print("...success.")

    print("Test read/write .photon file...")
    filepath = '/home/nard/PhotonFile/test/bunny.photon'
    filepath_new = '/home/nard/PhotonFile/test/bunny2.photon'
    org_filesize = os.path.getsize(filepath)
    photonfile = PhotonFile()
    #photonfile.load()
    photonfile.load(filepath)
    photonfile.load(filepath)  # do this 2 time to check clear old vars
    photonfile.save(filepath_new)
    new_filesize = os.path.getsize(filepath_new)
    assert new_filesize == org_filesize
    print("...success.")

    print("Test layers.count / layers.last / layers.height / volume...")
    filepath = '/home/nard/PhotonFile/test/bunny.photon'
    photonfile.load(filepath)
    assert photonfile.layers.count() == 1716
    assert photonfile.layers.last() == 1716 - 1
    assert photonfile.layers.height(0) == 0.05
    assert photonfile.volume(retUnit='ml') == 9.0
    print("...success.")

    print("Test Property get/set...")
    dlpWidth_write = 2560
    prevWidth_write = 320
    layerHeight_write = 0.04
    photonfile.setProperty("Resolution X", dlpWidth_write)
    photonfile.previews.setProperty(0, "Resolution X", prevWidth_write)
    photonfile.layers.setProperty(0, "Layer height (mm)", layerHeight_write)
    dlpWidth_read = photonfile.getProperty("Resolution X")
    prevWidth_read = photonfile.previews.getProperty(0, "Resolution X")
    layerHeight_read = photonfile.layers.getProperty(0, "Layer height (mm)")
    assert dlpWidth_read == dlpWidth_write
    assert prevWidth_read == prevWidth_write
    assert layerHeight_read == layerHeight_write
    print("...success.")

    print("Test layerimage save to file...")
    filepath0 = '/home/nard/PhotonFile/test/images/test0.png'
    filepath4 = '/home/nard/PhotonFile/test/images/test4.png'
    photonfile.layers.save(0, filepath0)
    photonfile.layers.save(4, filepath4)
    print("...success.")

    print("Test image insert to layer...")
    filepath0 = '/home/nard/PhotonFile/test/images/test0.png'
    filepath4 = '/home/nard/PhotonFile/test/images/test4.png'
    photonfile.layers.insert(filepath4, 4)
    photonfile.layers.insert(filepath0, 0)
    assert photonfile.layers.count() == 1716 + 2
    print("...success.")

    print("Test layer delete...")
    photonfile.layers.delete(0)
    photonfile.layers.delete(4)
    assert photonfile.layers.count() == 1716
    photonfile.save(filepath_new)
    new_filesize = os.path.getsize(filepath_new)
    assert new_filesize == org_filesize
    print("...success.")

    print("Test image encoding...")
    filepath = '/home/nard/PhotonFile/test/images/test.png'
    filepath_new = '/home/nard/PhotonFile/test/images/test2.png'
    photonfile.layers.insert(filepath, 4)
    photonfile.layers.save(4, filepath_new)
    org_imgfilesize = os.path.getsize(filepath)
    org_imgobjsize = PIL.Image.open(filepath).size
    new_imgfilesize = os.path.getsize(filepath_new)
    new_imgobjsize = PIL.Image.open(filepath_new).size
    assert (new_imgobjsize == org_imgobjsize)
    assert (new_imgfilesize == org_imgfilesize)
    print("...success.")

    print("Test layer replace layer with new image...")
    photon_filepath_org = '/home/nard/PhotonFile/test/bunny.photon'
    photonfile.load(photon_filepath_org)
    img_filepath4 = '/home/nard/PhotonFile/test/images/test4.png'
    photonfile.layers.replace(4, img_filepath4)
    assert photonfile.layers.count() == 1716
    photon_filepath_new = '/home/nard/PhotonFile/test/bunny2.photon'
    photonfile.save(photon_filepath_new)
    org_filesize = os.path.getsize(photon_filepath_org)
    new_filesize = os.path.getsize(photon_filepath_new)
    assert new_filesize == org_filesize
    print("...success.")

    print("Test append photonfile with new image...")
    photon_filepath_org = '/home/nard/PhotonFile/test/bunny.photon'
    photon_filepath_new = '/home/nard/PhotonFile/test/bunny2.photon'
    photonfile.load(photon_filepath_org)
    img_filepath4 = '/home/nard/PhotonFile/test/images/test4.png'
    photonfile.layers.append(img_filepath4)
    photonfile.layers.delete(photonfile.layers.last())
    photonfile.save(photon_filepath_new)
    assert new_filesize == org_filesize
    print("...success.")

    print("Save All...")
    photon_filepath_org = '/home/nard/PhotonFile/test/bunny.photon'
    photonfile.load(photon_filepath_org)
    photon_dirpath_new = '/home/nard/PhotonFile/test/bunny.img'
    photonfile.layers.saveAll(photon_dirpath_new)
    print("...success.")

    print("get All...")
    print("...success.")

    print("Save Replace...")
    print("...success.")

    print("Test copy image (via clipboard)...")
    print("...success.")

    print("Test cut/paste image (via clipboard)...")
    print("...success.")

    print("Test undo (via clipboard)...")
    print("...success.")

    print("Save Preview...")
    print("...success.")

    print("Replace Preview...")
    print("...success.")

    return
Ejemplo n.º 3
0
	def __init__(self, svgfilename, scale=1,
				outputpath=None,       # should end with '/'
				layerheight=0.05,
				photonfilename=None,   # keep outputpath=None if output to photonfilename
				normalexposure=8.0,
				bottomexposure=90,
				bottomlayers=8,
				offtime=6.5,
				gui=False
				):

		# Set Gui
		self.gui=gui

		# Get path of script/exe for local resources like iconpath and newfile.photon
		if getattr(sys, 'frozen', False):# frozen
			self.installpath = os.path.dirname(sys.executable)
		else: # unfrozen
			self.installpath = os.path.dirname(os.path.realpath(__file__))
		if gui:
			import tkinter as tk
			from tkinter import ttk
			# Construct window            
			self.popup = tk.Tk()#tk.Toplevel()
			self.popup.geometry('240x32')
			# Set window icon
			img=tk.PhotoImage(file=os.path.join(self.installpath,'PhotonSlicer.gif'))
			self.popup.tk.call('wm','iconphoto',self.popup._w,img)
			#tk.Label(self.popup, text="Slicing...").grid(row=0, column=0)
			self.popup.title("Slicing...")
			self.progress_var = tk.DoubleVar()
			progress_bar = ttk.Progressbar(self.popup, variable=self.progress_var, maximum=100, length=240)
			progress_bar.pack(fill=tk.Y, expand=1, side=tk.BOTTOM)

		# Measure how long it takes
		t1 = time.time()

		# Setup output path
		if outputpath==None and photonfilename==None:return

		#create path if not exists
		if not outputpath==None:
			if not os.path.exists(outputpath):
				os.makedirs(outputpath)

		# if we output to PhotonFile we need a place to store RunLengthEncoded images
		if not photonfilename==None:
			rlestack=[]

		# read and parse svg file
		xmldoc = minidom.parse(svgfilename)
		layers = xmldoc.getElementsByTagName('g')

		#contourColor = (255, 255, 255)  # alpha 255 is NOT transparent
		#contourColor = (255)  # alpha 255 is NOT transparent
		# innerColor = (0, 0, 255)
		innerColor = (128)

		scale=scale/0.047

		# draw layer for layer
		sliceNr=0
		nrSlices=len(layers)
		pLayers=[]
		for layer in layers:
			layer_id = layer.attributes['id'].value
			layer_z  = layer.attributes['slic3r:z'].value
			layer_polygons =layer.getElementsByTagName('polygon')
			img = numpy.zeros((2560, 1440, 1), numpy.uint8)
			pPolys=[]
			for layer_polygon in layer_polygons:
				layer_polygon_points = layer_polygon.attributes['points'].value
				pointString=layer_polygon_points.replace(',',' ')
				np_points = numpy.fromstring(pointString,dtype=float,sep=' ')
				np_points = np_points * scale
				nr_points = np_points.size
				nr_coords = nr_points//2
				np_coords = np_points.reshape(nr_coords,2)
				pPolys.append(np_coords)

				x = np_coords[:, 0]
				z = np_coords[:, 1]
				self.cmin = (min(self.cmin[0],x.min()), min(self.cmin[1],z.min()))
				self.cmax = (max(self.cmax[0],x.max()), max(self.cmax[1],z.max()))

			pLayers.append(pPolys)
			sliceNr=sliceNr+1

			# Show progress in terminal
			if not self.gui:
				msg="Reading ... "+str(sliceNr)+" / " + str(nrSlices)
				sys.stdout.write (msg)
				sys.stdout.write('\r')
				sys.stdout.flush()

		print("")

		# Center model and put on base
		trans    =  [0, 0]
		trans[0] = -(self.cmax[0] - self.cmin[0]) / 2 - self.cmin[0]
		trans[1] = -(self.cmax[1] - self.cmin[1]) / 2 - self.cmin[1]

		# We want the model centered in 2560x1440
		# 2560x1440 pixels equals 120x67
		trans[0] = trans[0] + 1440 / 2
		trans[1] = trans[1] + 2560 / 2

		sliceNr=0
		nrSlices=len(layers)
		for pLayer in pLayers:
			img = numpy.zeros((2560, 1440, 1), numpy.uint8)

			for pPoly in pLayer:
				# Center numpy array of points which is returned for fast OGL model loading
				pPoly = pPoly + trans
				# Fill poly
				cv2.fillPoly(img, numpy.array([pPoly],dtype='int32'), color=innerColor)                    

			if photonfilename==None:
				cv2.imwrite(filename, img)
			else:
				imgarr8 = img
				img1D=imgarr8.flatten(0)
				rlestack.append(rleEncode.encodedBitmap_Bytes_numpy1DBlock(img1D))    

			# Show progress in terminal
			if not self.gui:
				msg="Saving ... "+str(sliceNr)+" / " + str(nrSlices)
				sys.stdout.write (msg)
				sys.stdout.write('\r')
				sys.stdout.flush()

			# Update GUI progress bar if gui active
			if self.gui:
				try: # Check if user aborted/closed window
					self.popup.update()
					progress=100*sliceNr/nrSlices
					self.progress_var.set(progress)
				except Exception:
					sys.exit() # quit() does not work if we make this an exe with cx_Freeze

			sliceNr += 1


		if not self.gui: print () # close progress stdout and go to new line
		                    
		if not photonfilename==None:
		    tempfilename=os.path.join(self.installpath,"newfile.photon")
		    photonfile=PhotonFile(tempfilename)
		    photonfile.readFile()
		    photonfile.Header["Layer height (mm)"]= PhotonFile.float_to_bytes(layerheight)
		    photonfile.Header["Exp. time (s)"]    = PhotonFile.float_to_bytes(normalexposure)
		    photonfile.Header["Exp. bottom (s)"]  = PhotonFile.float_to_bytes(bottomexposure)
		    photonfile.Header["# Bottom Layers"]  = PhotonFile.int_to_bytes(bottomlayers)
		    photonfile.Header["Off time (s)"]     = PhotonFile.float_to_bytes(offtime)
		    photonfile.replaceBitmaps(rlestack)
		    photonfile.writeFile(photonfilename)

		if not self.gui: print("Elapsed: ", "%.2f" % (time.time() - t1), "secs")


#test =  Svg2Slices(
#		svgfilename='STLs/pikachu_repaired.svg',
#		photonfilename="STLs/pikachu_svg.photon",
#		gui=False
#		)
Ejemplo n.º 4
0
    def __init__(
            self,
            stlfilename,
            scale=1,
            outputpath=None,  # should end with '/'
            layerheight=0.05,
            photonfilename=None,  # keep outputpath=None if output to photonfilename
            normalexposure=8.0,
            bottomexposure=90,
            bottomlayers=8,
            offtime=6.5,
            gui=False):
        # Set Gui
        self.gui = gui
        # Get path of script/exe for local resources like iconpath and newfile.photon
        if getattr(sys, 'frozen', False):  # frozen
            self.installpath = os.path.dirname(sys.executable)
        else:  # unfrozen
            self.installpath = os.path.dirname(os.path.realpath(__file__))
        if gui:
            import tkinter as tk
            from tkinter import ttk
            # Construct window
            self.popup = tk.Tk()  #tk.Toplevel()
            self.popup.geometry('240x32')
            # Set window icon
            img = tk.PhotoImage(
                file=os.path.join(self.installpath, 'PhotonSlicer.gif'))
            self.popup.tk.call('wm', 'iconphoto', self.popup._w, img)
            #tk.Label(self.popup, text="Slicing...").grid(row=0, column=0)
            self.popup.title("Slicing...")
            self.progress_var = tk.DoubleVar()
            progress_bar = ttk.Progressbar(self.popup,
                                           variable=self.progress_var,
                                           maximum=100,
                                           length=240)
            progress_bar.pack(fill=tk.Y, expand=1, side=tk.BOTTOM)

        # Measure how long it takes
        t1 = time.time()

        # Setup output path
        if outputpath == None and photonfilename == None: return

        #create path if not exists
        if not outputpath == None:
            if not os.path.exists(outputpath):
                os.makedirs(outputpath)

        # if we output to PhotonFile we need a place to store RunLengthEncoded images
        if not photonfilename == None:
            rlestack = []

        # Load 3d Model in memory
        points, normals = self.load_binary_stl(stlfilename, scale=scale)
        # Check if inside build area
        if (self.cmin[0] < 0 or self.cmin[2] < 0 or self.cmin[1] < 0
                or self.cmax[0] > 1440 or self.cmax[2] > 2560):
            size = (self.cmax[0] - self.cmin[0], self.cmax[1] - self.cmin[1],
                    self.cmax[2] - self.cmin[2])
            sizestr = "(" + str(int(size[0] * 0.047)) + "x" + str(
                int(size[2] * 0.047)) + ")"
            areastr = "(65x115)"
            errmsg = "Model is too big " + sizestr + "for build area " + areastr + ". Maybe try another orientation, use the scale argument (-s or --scale) or cut up the model."
            if not self.gui:
                print(errmsg)
            else:
                sys.tracebacklimit = None
                raise Exception(errmsg)
                sys.tracebacklimit = 0
            sys.exit(
            )  # quit() does not work if we make this an exe with cx_Freeze
        # extract x and z to make 2d normals and normalize these
        normals2D = numpy.delete(normals, 1, 1)
        l = numpy.sqrt(numpy.power(normals, 2).sum(-1))[..., numpy.newaxis]
        normals2D = 2 * normals2D / l

        # Slice settings
        #   model dimensions are in pixels/voxels of size 0.047mm,
        #   so we need to recalc layerheight in mm to voxelheight of 0.047mm
        layerHeight = layerheight / 0.047  # recalc to 0.047mm units
        maxHeight = self.modelheight  # modelheight is in 0.047mm units
        nrSlices = 1 + int(maxHeight / layerHeight)

        # Determine which triangles are in which slices
        slicepointindices = []
        # construct layers
        for sliceNr in range(nrSlices + 1):
            l = []
            slicepointindices.append(l)

        # map tris to layer
        # all coordinates are now in 0.047 size voxels
        # aso layerHeight is in 0.047 steps
        y = 1
        #print ("modelHeight,layerheight,nrSlices",maxHeight,layerheight,nrSlices)
        pointsAppended = 0
        for i in range(0, len(points), 3):
            p0 = points[i + 0]
            p1 = points[i + 1]
            p2 = points[i + 2]
            minY = min(p0[y], p1[y], p2[y])
            maxY = max(p0[y], p1[y], p2[y])
            minSlice = int(minY / layerHeight)
            maxSlice = int(maxY / layerHeight) + 1
            #print ("Tri:",i,minY,maxY,minSlice,maxSlice)
            for sliceNr in range(minSlice, maxSlice + 1):
                slicepointindices[sliceNr].append(i)
                #print ("append to",sliceNr)
            pointsAppended = pointsAppended + 1
        if (len(points) // 3 != pointsAppended):
            raise Exception(
                "Bug found. Not all triangles are stored in layers!")
        #print (len(points)//3,pointsAppended)
        #show layers
        #for sliceNr in range(nrSlices+1):
        #    print (sliceNr,len(slicepointindices[sliceNr]))

        # Slice model
        #contourColor = (255, 255, 255)  # alpha 255 is NOT transparent
        contourColor = (255)  # alpha 255 is NOT transparent
        # innerColor = (0, 0, 255)
        innerColor = (128)

        for sliceNr in range(0, nrSlices):
            # Filename for new slice
            sliceBottom = sliceNr * layerHeight
            sliceTop = sliceBottom + layerHeight
            if not outputpath == None:
                Sstr = "%04d" % sliceNr
                filename = outputpath + Sstr + ".png"

            # Start with empty image for slice (3 bytes depth is 2.5x slower than 1 byte depth)
            #img = numpy.zeros((2560, 1440, 3), numpy.uint8)
            img = numpy.zeros((2560, 1440, 1), numpy.uint8)

            # Clear fillpoints
            fillpoints = []
            """
            lines=[]
            nors=[]
            ps=[]
            """

            # Traverse all triangles
            for pidx in slicepointindices[sliceNr]:
                p0 = points[pidx + 0]
                p1 = points[pidx + 1]
                p2 = points[pidx + 2]
                n2d = normals2D[pidx // 3]
                # Check which part of triangle is inside slice
                polypoints = triInSlice.triInSlice(p0, p1, p2, sliceBottom,
                                                   sliceTop)
                # Draw filled poly, fillConvexPoly is much faster than fillPoly, but poly should be convex...
                if polypoints:
                    # if we do fill on all lines, do we need fillConvexPoly?
                    cv2.fillConvexPoly(img,
                                       numpy.array([polypoints],
                                                   dtype='int32'),
                                       color=contourColor)
                    # Add points for which to floodfillpoints using normal but only if normal not along y
                    if not (n2d[0] == 0 and n2d[1] == 0):
                        nrpoints = len(polypoints)
                        for idx in range(nrpoints):
                            pfrom = polypoints[idx]
                            pto = polypoints[(idx + 1) % nrpoints]
                            pmid = ((pfrom[0] + pto[0]) / 2,
                                    (pfrom[1] + pto[1]) / 2)
                            pfill = (int(
                                (pmid[0] - n2d[0])), int((pmid[1] - n2d[1])))
                            # Check if point inside triangle(s) - https://stackoverflow.com/questions/2049582/how-to-determine-if-a-point-is-in-a-2d-triangle
                            # Pikachu_repaired.STL with check 9-11sec, without 10-12sec
                            #"""
                            #inTri1=False
                            #inTri2=False
                            """
                            inTri1=Stl2Slices.PointInTriangle(pfill,
                            #inTri1=triInSlice.PointInTriangle(pfill,
                                                              polypoints[(idx+0) % nrpoints],
                                                              polypoints[(idx+1) % nrpoints],
                                                              polypoints[(idx+2) % nrpoints])
                            if nrpoints>3:
                                inTri2=Stl2Slices.PointInTriangle(pfill,
                                #inTri2=triInSlice.PointInTriangle(pfill,
                                                                  polypoints[(idx+0) % nrpoints],
                                                                  polypoints[(idx+1) % nrpoints],
                                                                  polypoints[(idx-1) % nrpoints])
                            else:
                                inTri2=inTri1
                            if not inTri1 and not inTri2:
                                fillpoints.append(pfill)
                            """
                            fillpoints.append(pfill)
                            """
                            pfrom = polypoints[idx % nrpoints]#(int(pfrom[0]),int(pfrom[1]))
                            pto   = polypoints[(idx+1) % nrpoints] #(int(pto[0]), int(pto[1]))
                            lines.append((pfrom,pto))
                            nors.append(n2d)
                            ps.append([p0,p1,p2])
                            """

            # Floodfill all points
            tester = img.copy()
            nrTests = 0
            nrFills = 0
            nrRedos = 0
            nr = 0

            #fillPoint=(100,30)
            #cv2.circle(img,fillPoint,10,192,1)
            #cv2.floodFill(img, mask=None, seedPoint=fillPoint, newVal=100)  # 80% of time
            #cv2.floodFill(img, mask=None, seedPoint=fillPoint, newVal=100)  # 80% of time
            #cv2.imwrite("STLs/legocog/_test.png", img)
            #quit()

            #for idx,fillPoint in enumerate(fillpoints):
            """
            for y in range(0,2560):            
                oldcol=0
                inShape=False
                for x in range (0,1440):
                    col=1#img[y,x]
                    if oldcol!=col: 
                        inShape!=inShape
                        col=oldcol    
                    if inShape:
                        img[y,x]=innerColor
            """

            for fillPoint in fillpoints:
                # Check if fill is necessary at fillpoint (if fillpoint still has background color = 0,0,0)) and not fill color (=innerColor)
                pxColor = (
                    img[fillPoint[1], fillPoint[0], 0]  #,
                    #img[fillPoint[1], fillPoint[0], 1],
                    #img[fillPoint[1], fillPoint[0], 2]
                )
                #if pxColor == (0, 0, 0):
                if pxColor == (0):
                    # Do a testfill on tester
                    cv2.floodFill(tester,
                                  mask=None,
                                  seedPoint=fillPoint,
                                  newVal=innerColor)  # 80% of time
                    nrTests += 1
                    # And check if fill (on tester) reaches (0,0) and thus we are filling outside of model contour
                    #outerColor = (tester[0, 0, 0], tester[0, 0, 1], tester[0, 0, 2])
                    outerColor = (tester[0, 0, 0])
                    # If fill was necessary and fill in tester stayed inside model, then we apply fill on img
                    #if outerColor == (0, 0, 0):
                    if outerColor == (0):
                        cv2.floodFill(img,
                                      mask=None,
                                      seedPoint=fillPoint,
                                      newVal=innerColor)
                        nrFills += 1
                    else:  # we destroyed tester and have to repair it by making a copy of img
                        """
                        fname=("STLs/3DBenchy/%04d" % sliceNr) +"-"+("%04d" % nrTests)+".png"
                        print (fname)
                        print ("fillPoint,oldColor: ",fillPoint,pxColor)
                        print ("line,normal       : ",lines[idx],nors[idx])
                        print ("(0,0):",outerColor)
                        print ("3D Tri:")
                        q0=(0,0,0)
                        q1 = (ps[idx][1][0]-ps[idx][0][0],ps[idx][1][1]-ps[idx][0][1],ps[idx][1][2]-ps[idx][0][2])
                        q2 = (ps[idx][2][0] - ps[idx][0][0], ps[idx][2][1] - ps[idx][0][1], ps[idx][2][2] - ps[idx][0][2])
                        print("p0: {:.3f} {:.3f} {:.3f}".format(ps[idx][0][0], ps[idx][0][1], ps[idx][0][2]))
                        print("p1: {:.3f} {:.3f} {:.3f}".format(ps[idx][1][0], ps[idx][1][1], ps[idx][1][2]))
                        print("p2: {:.3f} {:.3f} {:.3f}".format(ps[idx][2][0], ps[idx][2][1], ps[idx][2][2]))
                        print ("q0->1: {:.3f} {:.3f} {:.3f}".format(q1[0],q1[1],q1[2]))
                        print ("q0->2: {:.3f} {:.3f} {:.3f}".format(q2[0], q2[1], q2[2]))

                        #cv2.floodFill(tester, mask=None, seedPoint=fillPoint, newVal=48)  # 80% of time
                        fillPointColor = (128)
                        lines[idx]=((int(lines[idx][0][0]),int(lines[idx][0][1])),(int(lines[idx][1][0]), int(lines[idx][1][1])))
                        cv2.line(img, pt1=lines[idx][0], pt2=lines[idx][1], color=48, thickness=1)
                        cv2.line(img, pt1=fillPoint, pt2=fillPoint, color=fillPointColor, thickness=1)
                        cv2.circle(img,fillPoint,20,fillPointColor,1)
                        cv2.imwrite(fname, img)
                        quit()
                        """
                        tester = img.copy()
                        nrRedos += 1
            # Debug: print nr of retries
            #print("sliceNr, nrTests, nrFills, nrRedos", sliceNr,nrTests, nrFills, nrRedos)

            # Debug: mark fill points
            # fillPointColor = (0,255,255)
            """
            fillPointColor = (128)
            for fillpoint in fillpoints:
                # Debug
                cv2.line(img, pt1=fillpoint, pt2=fillpoint, color=fillPointColor, thickness=1)
            """

            # Save image
            #if (img[0, 0, 0], img[0, 0, 1], img[0, 0, 2]) == (0, 0, 0):
            if (img[0, 0]) == (0):
                if photonfilename == None:
                    #print("Saved ",sliceNr, "/", nrSlices, "->", filename)
                    cv2.imwrite(filename, img)
                else:
                    #print("Encoded", sliceNr, "/", nrSlices, "->", filename)
                    # Convert slice to 1 color component (keep white and red)
                    #imgarr8 = img[:, :, 2]
                    imgarr8 = img
                    # we need to rotate img 90 degrees
                    #imgarr8 = numpy.rot90(imgarr8, axes=(1, 0))  # we need 1440x2560
                    # encode bitmap numpy array to rle
                    img1D = imgarr8.flatten(0)
                    rlestack.append(
                        rleEncode.encodedBitmap_Bytes_numpy1DBlock(img1D))
                    #rlestack.append(bytes([0x00]))
            else:
                if not self.gui: print("Slice Error: ", filename)

            # Show progress in terminal
            if not self.gui:
                msg = "Slicing ... " + str(sliceNr) + " / " + str(nrSlices)
                sys.stdout.write(msg)
                sys.stdout.write('\r')
                sys.stdout.flush()

            # Update GUI progress bar if gui active
            if self.gui:
                try:  # Check if user aborted/closed window
                    self.popup.update()
                    progress = 100 * sliceNr / nrSlices
                    self.progress_var.set(progress)
                except Exception:
                    sys.exit(
                    )  # quit() does not work if we make this an exe with cx_Freeze

        if not self.gui: print()  # close progress stdout and go to new line

        if not photonfilename == None:
            tempfilename = os.path.join(self.installpath, "newfile.photon")
            photonfile = PhotonFile(tempfilename)
            photonfile.readFile()
            photonfile.Header["Layer height (mm)"] = PhotonFile.float_to_bytes(
                layerheight)
            photonfile.Header["Exp. time (s)"] = PhotonFile.float_to_bytes(
                normalexposure)
            photonfile.Header["Exp. bottom (s)"] = PhotonFile.float_to_bytes(
                bottomexposure)
            photonfile.Header["# Bottom Layers"] = PhotonFile.int_to_bytes(
                bottomlayers)
            photonfile.Header["Off time (s)"] = PhotonFile.float_to_bytes(
                offtime)
            photonfile.replaceBitmaps(rlestack)
            photonfile.writeFile(photonfilename)

        if not self.gui:
            print("Elapsed: ", "%.2f" % (time.time() - t1), "secs")
Ejemplo n.º 5
0
    def __init__(
        self,
        stlfilename,
        scale=1,
        outputpath=None,  # should end with '/'
        layerheight=0.05,
        photonfilename=None,  # keep outputpath=None if output to photonfilename
        normalexposure=8.0,
        bottomexposure=90,
        bottomlayers=8,
        offtime=6.5,
    ):

        self.viewport = GL_Viewport.Viewport()

        # Get path of script/exe for local resources like iconpath and newfile.photon
        if getattr(sys, 'frozen', False):  # frozen
            self.installpath = os.path.dirname(sys.executable)
        else:  # unfrozen
            self.installpath = os.path.dirname(os.path.realpath(__file__))

        # Measure how long it takes
        t1 = time.time()

        # Setup output path
        if outputpath == None and photonfilename == None: return

        #create path if not exists
        if not outputpath == None:
            if not os.path.exists(outputpath):
                os.makedirs(outputpath)

        # if we output to PhotonFile we need a place to store RunLengthEncoded images
        if not photonfilename == None:
            rlestack = []

        # Load 3d Model in memory
        points, normals = self.load_binary_stl(stlfilename, scale=scale)

        # Check if inside build area
        size = (self.cmax[0] - self.cmin[0], self.cmax[1] - self.cmin[1],
                self.cmax[2] - self.cmin[2])
        if size[0] > 65 or size[1] > 115:
            sizestr = "(" + str(int(size[0])) + "x" + str(int(size[2])) + ")"
            areastr = "(65x115)"
            errmsg = "Model is too big " + sizestr + " for build area " + areastr + ". Maybe try another orientation, use the scale argument (-s or --scale) or cut up the model."
            if not self.gui:
                print(errmsg)
            else:
                sys.tracebacklimit = None
                raise Exception(errmsg)
                sys.tracebacklimit = 0
            sys.exit(
            )  # quit() does not work if we make this an exe with cx_Freeze

        # Load mesh
        #print ("loading mesh")
        self.viewport.loadMesh(points, normals, self.cmin, self.cmax)
        #self.viewport.display() # this will loop until window is closed
        self.viewport.draw()

        microns = layerheight * 1000  #document.getElementById("height").value;
        bounds = self.viewport.getBounds()
        #print ((bounds['zmax']-bounds['zmin']) , self.viewport.printer.getGLscale())
        #quit()
        zrange_mm = (bounds['zmax'] -
                     bounds['zmin']) / self.viewport.printer.getGLscale()
        count = math.ceil(zrange_mm * 1000 / microns)
        #print ("b",bounds)
        #print ("z",zrange_mm)
        #print ("m",microns)
        #print ("c",count)

        if not photonfilename == None:
            rlestack = []

        for i in range(0, count):
            data = self.viewport.getSliceAt(i / count)
            img = data.reshape(2560, 1440, 4)
            imgarr8 = img[:, :, 1]
            if photonfilename == None:
                Sstr = "%04d" % i
                filename = outputpath + Sstr + ".png"
                print(i, "/", count, filename)
                cv2.imwrite(filename, imgarr8)
            else:
                img1D = imgarr8.flatten(0)
                rlestack.append(
                    rleEncode.encodedBitmap_Bytes_numpy1DBlock(img1D))

        if not photonfilename == None:
            tempfilename = os.path.join(self.installpath, "newfile.photon")
            photonfile = PhotonFile(tempfilename)
            photonfile.readFile()
            photonfile.Header["Layer height (mm)"] = PhotonFile.float_to_bytes(
                layerheight)
            photonfile.Header["Exp. time (s)"] = PhotonFile.float_to_bytes(
                normalexposure)
            photonfile.Header["Exp. bottom (s)"] = PhotonFile.float_to_bytes(
                bottomexposure)
            photonfile.Header["# Bottom Layers"] = PhotonFile.int_to_bytes(
                bottomlayers)
            photonfile.Header["Off time (s)"] = PhotonFile.float_to_bytes(
                offtime)
            photonfile.replaceBitmaps(rlestack)
            photonfile.writeFile(photonfilename)

        print("Elapsed: ", "%.2f" % (time.time() - t1), "secs")
def benchmarks():

    print("BENCHMARK...")
    photonfilepath = '/home/nard/PhotonFile/test/bunny.cbddlp'
    photonfile = PhotonFile(photonfilepath)
    photonfile.load()
    n = 50

    print()
    print(" UNITS...")

    #PIL.Image.open
    imgfilepath = '/home/nard/PhotonFile/test/images/test.png'
    t = time.time()
    for i in range(0, n):
        im = PIL.Image.open(imgfilepath)
        nparr = numpy.asarray(im)
    d = (time.time() - t) / n
    print(f"  PIL.Image.open x 1000        : {round(1000*d,2)} sec")

    #cv2.imread
    imgfilepath = '/home/nard/PhotonFile/test/images/test.png'
    t = time.time()
    for i in range(0, n):
        im = cv2.imread(imgfilepath)
        nparr = im
    d = (time.time() - t) / n
    print(f"  cv2.imread x 1000            : {round(1000*d,2)} sec")

    #PIL.Image.save (comp level = 3 is fastest)
    imgfilepath = '/home/nard/PhotonFile/test/images/test.png'
    imgfilepath_new = '/home/nard/PhotonFile/test/images/test_save2pil.png'
    im = PIL.Image.open(imgfilepath)
    t = time.time()
    for i in range(0, n):
        im.save(imgfilepath_new, compress_level=3)
    d = (time.time() - t) / n
    print(f"  PIL.Image.save(comp=6) x 1000: {round(1000*d,2)} sec")

    #CV.imwrite
    imgfilepath = '/home/nard/PhotonFile/test/images/test.png'
    imgfilepath_new = '/home/nard/PhotonFile/test/images/test_save2cv2.png'
    img = cv2.imread(imgfilepath, -1)
    t = time.time()
    for i in range(0, n):
        cv2.imwrite(imgfilepath_new, img)
        #cv2.imwrite(imgfilepath_new,img,[int(cv2.IMWRITE_PNG_COMPRESSION), 1])
    d = (time.time() - t) / n
    print(f"  CV2.Image.write x 1000       : {round(1000*d,2)} sec")

    #PIL.Image -> Numpy 1D
    t = time.time()
    for i in range(0, n):
        np = numpy.asarray(im)
        if np.ndim == 3: np = np[:, :, 0]
        npf = np.flatten()
    d = (time.time() - t) / n
    print(f"  PIL.Image -> Numpy 1D x 1000 : {round(1000*d,2)} sec")

    #cv2.Image -> Numpy 1D
    t = time.time()
    for i in range(0, n):
        np = numpy.array(img)
        if np.ndim == 3: np = np[:, :, 0]
        npf = np.flatten()
    d = (time.time() - t) / n
    print(f"  CV2.Image -> Numpy 1D x 1000 : {round(1000*d,2)} sec")

    #decodeRLE
    rleData = photonfile.layers.get(3, retType='rle')
    t = time.time()
    for i in range(0, n):
        nparr = RLE.decodeRLE28bImage(rleData)
    d = (time.time() - t) / n
    print(f"  RLE.decodeRLE28bImage x 1000 : {round(1000*d,2)} sec")

    #encodeRLE
    t = time.time()
    for i in range(0, n):
        rleData = RLE.encode8bImage2RLE(npf)
    d = (time.time() - t) / n
    print(f"  RLE.encode8bImage2RLE x 1000 : {round(1000*d,2)} sec")

    #get nrpixels
    rleData = photonfile.layers.get(4, retType='rle')
    t = time.time()
    for i in range(0, n):
        pixelsInLayer = RLE.RLEPixels(rleData)
    d = (time.time() - t) / n
    print(f"  RLE.RLEPixels x 1000         : {round(1000*d,2)} sec")

    #get rle bytes
    t = time.time()
    for i in range(0, n):
        rleData = photonfile.layers.get(4, 'rle')
    d = (time.time() - t) / n
    print(f"  layers.get(4,'rle') x 1000   : {round(1000*d,2)} sec")

    #get numpy bytes
    t = time.time()
    for i in range(0, n):
        numpy2D = photonfile.layers.get(4, retType='numpy')
    d = (time.time() - t) / n
    print(f"  layers.get(4,'numpy') x 1000 : {round(1000*d,2)} sec")

    #get volume
    t = time.time()
    for i in range(0, n):
        numpy2D = photonfile.volume()
    d = (time.time() - t) / n
    print(f"  photonfile.volume() x 1      : {round(d,2)} sec")

    print()
    print(" EXPORT/IMPORT...")

    #export image from rle data in layer using PIL.Image.save
    imgfilepath_new = '/home/nard/PhotonFile/test/images/test_export2pil.png'
    t = time.time()
    for i in range(0, n):
        rleData = photonfile.layers.get(3, retType='rle')
        numpyArray1Duint8 = RLE.decodeRLE28bImage(rleData)
        numpyArray2Duint8 = numpyArray1Duint8.reshape(2560, 1440)
        im = PIL.Image.fromarray(numpyArray2Duint8)
        im.save(imgfilepath_new, compress_level=3)
    d = (time.time() - t) / n
    print(f"  RLE->PIL.Image.save x 1000   : {round(1000*d,2)} sec")

    #export image from rle data in layer using CV2.imwrite
    imgfilepath_new = '/home/nard/PhotonFile/test/images/test_export2cv2.png'
    t = time.time()
    for i in range(0, n):
        rleData = photonfile.layers.get(3, retType='rle')
        numpyArray1Duint8 = RLE.decodeRLE28bImage(rleData)
        numpyArray2Duint8 = numpyArray1Duint8.reshape(2560, 1440, 1)
        cv2.imwrite(imgfilepath_new, numpyArray2Duint8)
    d = (time.time() - t) / n
    print(f"  RLE->CV2.Image.write x 1000  : {round(1000*d,2)} sec")

    #import image from rle data in layer using PIL.Image.open
    imgfilepath_new = '/home/nard/PhotonFile/test/images/test.png'
    t = time.time()
    for i in range(0, n):
        im = PIL.Image.open(imgfilepath_new)
        npArray = numpy.asarray(im)
        if npArray.ndim == 3:
            npArray = npArray[:, :, 0]
        npArray = npArray.flatten()
        rleData = RLE.encode8bImage2RLE(npArray)
    d = (time.time() - t) / n
    imgfilepath_chk = '/home/nard/PhotonFile/test/images/test_checkload_pil.png'
    numpyArray1Duint8 = RLE.decodeRLE28bImage(rleData)
    numpyArray2Duint8 = numpyArray1Duint8.reshape(2560, 1440)
    im = PIL.Image.fromarray(numpyArray2Duint8)
    im.save(imgfilepath_chk, compress_level=3)
    print(f"  PIL.Image.open->RLE x 1000   : {round(1000*d,2)} sec")

    #import image from rle data in layer using CV2.imread
    imgfilepath_new = '/home/nard/PhotonFile/test/images/test.png'
    t = time.time()
    for i in range(0, n):
        npArray = cv2.imread(imgfilepath_new,
                             cv2.IMREAD_UNCHANGED)  # is native numpy array
        if npArray.ndim == 3:
            npArray = npArray[:, :, 0]
        npArray = npArray.flatten()
        rleData = RLE.encode8bImage2RLE(npArray)
    d = (time.time() - t) / n
    imgfilepath_chk = '/home/nard/PhotonFile/test/images/test_checkload_cv2.png'
    numpyArray1Duint8 = RLE.decodeRLE28bImage(rleData)
    numpyArray2Duint8 = numpyArray1Duint8.reshape(2560, 1440, 1)
    cv2.imwrite(imgfilepath_chk, numpyArray2Duint8)
    print(f"  CV2.imread->RLE x 1000       : {round(1000*d,2)} sec")
Ejemplo n.º 7
0
def readPhotonFile(filename):
    global files
    global layerHeight

    photonfile = PhotonFile()
    photonfile.load(filename)

    # Check if file not already present
    for file in files:
        if file[1] == filename:
            root.option_add('*Dialog.msg.font', 'Helvetica 10')
            messagebox.showerror('File already loaded',
                                 'You already loaded this file.')
            return

    # If first file we copy properties
    if len(files) == 0:
        layerHeight = photonfile.getProperty("Layer height (mm)")

        entry_BottomLayers.delete(0, tkinter.END)
        entry_NormalExp.delete(0, tkinter.END)
        entry_BottomExp.delete(0, tkinter.END)
        entry_Offtime.delete(0, tkinter.END)
        entry_BottomLayers.insert(0, photonfile.getProperty("# Bottom Layers"))
        entry_NormalExp.insert(0, photonfile.getProperty("Exp. time (s)"))
        entry_BottomExp.insert(0, photonfile.getProperty("Exp. bottom (s)"))
        entry_Offtime.insert(0, photonfile.getProperty("Off time (s)"))

    # Check if layerheight is same as other layerheights
    if photonfile.getProperty("Layer height (mm)") != layerHeight:
        root.option_add('*Dialog.msg.font', 'Helvetica 10')
        messagebox.showerror('Different Layer Height',
                             'All photonfiles should have samen layerheight.')
        return

    # set layerheight
    label_layerHeight['text'] = str(layerHeight)

    # Show messagebox to let use know we are analyzing
    app = showProgress(root, "Analyzing...", 0, 1, True, False, False)

    xmin, ymin, xmax, ymax = 9999, 9999, 0, 0
    for layerNr in range(photonfile.layers.count()):
        im = photonfile.layers.get(
            layerNr, 'n')  # 2560 rows, 1440 cols; element is called im[y,x]
        res = cv2.findContours(im.copy(), cv2.RETR_EXTERNAL,
                               cv2.CHAIN_APPROX_SIMPLE)
        # In the current OpenCV's master branch the return statements have changed, see http://docs.opencv.org/modules/imgproc/doc/structural_analysis_and_shape_descriptors.html?highlight=findcontours.
        if len(res) == 3: _, contours, hierarchy = res
        if len(res) == 2: contours, hierarchy = res
        #contours, hierarchy = cv2.findContours(im.copy(),cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_SIMPLE)
        idx = 0
        for cnt in contours:
            idx += 1
            x, y, w, h = cv2.boundingRect(cnt)
            xmin = min(x, xmin)
            ymin = min(y, ymin)
            xmax = max(x + w, xmax)
            ymax = max(y + h, ymax)

        app.setProgressPerc(int(100 * layerNr / photonfile.layers.count()))

    app.hide()

    #put some margin around regions
    margin = 10

    def clamp(n, smallest, largest):
        return max(smallest, min(n, largest))

    xmin = clamp(xmin - margin, 0, 1439)
    ymin = clamp(ymin - margin, 0, 2559)
    xmax = clamp(xmax + margin, 0, 1439)
    ymax = clamp(ymax + margin, 0, 2559)

    #files entries are tuples of:filename,photonfile classobject,position,size
    files.append([
        len(files), filename, photonfile, (xmin, ymin),
        (xmax - xmin, ymax - ymin)
    ])

    print("Read:", filename, photonfile.layers.count(), (xmin, ymin),
          (xmax - xmin, ymax - ymin))
    print("Read:", files[len(files) - 1])

    basename = os.path.basename(filename)
    barename = os.path.splitext(basename)[0]
    item = str(len(files)) + " " + barename
    listbox.insert(tkinter.END, item)

    return photonfile
Ejemplo n.º 8
0
def mnSaveAs():
    global objects
    # Check if we got a filename
    hideHiddenFilesInDialog()
    filename = tkinter.filedialog.asksaveasfilename(
        initialdir=".",
        title="Select file",
        filetypes=(("photon files", "*.photon"), ("all files", "*.*")))
    if not filename: return

    print("Saving...", filename)

    # Create new photonfile
    global entry_BottomLayers, entry_BottomExp, entry_NormalExp, entry_Offtime, layerHeight, scale
    outPhotonFile = PhotonFile()
    outPhotonFile.new()
    outPhotonFile.layers.clear()
    outPhotonFile.filename = filename
    outPhotonFile.setProperty("# Bottom Layers", int(entry_BottomLayers.get()))
    outPhotonFile.setProperty("Exp. time (s)", float(entry_NormalExp.get()))
    outPhotonFile.setProperty("Exp. bottom (s)", float(entry_BottomExp.get()))
    outPhotonFile.setProperty("Off time (s)", float(entry_Offtime.get()))
    outPhotonFile.setProperty("Layer height (mm)", float(layerHeight))
    #return

    # Check max layer
    nrLayers = 0
    for obj in objects:
        file = obj[0]
        photonfile = file[2]
        nrLayers = max(nrLayers, photonfile.layers.count())

    # Show messagebox to let use know we are analyzing
    app = showProgress(root, "Merging...", 0, 1, True, False, False)

    # Construct each layer
    for layerNr in range(nrLayers):
        totIm = numpy.zeros((2560, 1440, 1), dtype=numpy.uint8)
        for obj in objects:
            file, xdest, ydest, wdest, hdest, rot = obj
            #print ("obj: ",xdest,ydest,wdest,hdest,rot,file)
            (xdest, ydest) = (ydest, xdest)
            xdest = int(xdest / scale)
            ydest = int(ydest / scale)
            wdest, hdest = file[4]
            if rot == 90: wdest, hdest = hdest, wdest
            #if layerNr<10:
            #    print ("dest2",xdest,ydest,wdest,hdest)
            #file entries are tuples of:filename,photonfile classobject,position,size
            idx, filename, photonfile, (xsrc, ysrc), (wsrc, hsrc) = file
            # check if this photonfile has enough layers
            #print (photonfile.layers.count(),">",layerNr)
            if layerNr < photonfile.layers.count():
                # Get full layer
                locIm = photonfile.layers.get(layerNr, 'i')
                # Get active region in layer
                locIm = locIm[ysrc:ysrc + hsrc, xsrc:xsrc + wsrc]
                # Rotate if requested
                #print ("shape1:",locIm.shape)
                if rot == 90: locIm = numpy.rot90(locIm)
                #print ("shape2:",locIm.shape)
                # Put in destination
                #print ("dest:  [",ydest,":",ydest+hdest,",",xdest,":",xdest+wdest,"]")
                totIm[ydest:ydest + hdest, xdest:xdest + wdest] = locIm
                if layerNr == 10:
                    print("write")
                    cv2.imwrite("test/out1.png", locIm)
                    cv2.imwrite("test/out2.png", totIm)

        # For some res
        outPhotonFile.layers.append(totIm)
        #if layerNr>3: return

        app.setProgressPerc(int(100 * layerNr / nrLayers))

    app.hide()

    outPhotonFile.save()