chjmartin2 Posted August 23 Share Posted August 23 Hi, I have been hard at work on creating a new tool for the Aquarius+ which I hope to expand to also be useful for the Aquarius as well. Currently, it is a GUI-based windows application that will allow you to convert high quality images to your Aquarius+. The input format can be any sized GIF, BMP, PNG or JPG. The output format is BMP4 which is 160x200 with 16 colors out of a 4096 available colors. It uses K-means++ to determine the optimal colors. It has various options for dithering. There is also a executable included called ViewBM4 which will allow you to preview the images. If you have the latest version of the Aquarius+ emulator or firmware, then in basic you can use the below command to display the image: load bitmap "filename.BM4":screen 0,3:pause My hope is to improve this to be a multi-format image workshop for both the classic Aquarius and the Aquarius+. I have code to convert images to the text mode on the original system. There are a myriad of other options on the Aquarius+ as well. I think having an editor would be great, at least for the graphics modes as Matt P's text editor is already near perfect if not so. I'd like to add the ability to manually adjust the palette, median-cut color selection and of course add all of the other potential formats including text mode, etc. Would love to hear from anybody that decides to give it a try. Thanks, Chris APImageWorks_V1.0.zip 2 1 Quote Link to comment Share on other sites More sharing options...
1stage Posted August 24 Share Posted August 24 I'm loving version 1.0! I can't wait to see the next revision! Quote Link to comment Share on other sites More sharing options...
chjmartin2 Posted September 15 Author Share Posted September 15 It's here! I am excited to release Aquarius+ Imageworks Version 1.1. Here are the new features: Brightness/Contrast Controls New Input Scale Methods: Stretch, Fill, Center, Fit, Aspect Fill to allow management of letterbox and other aspect ratio conserving methods Aspect Ratio Correct- Input Image assumes proper aspect ratio relative to 2:1 aspect ratio of output image (can be disabled) Fixed Bicubic Scale and added Lanczos Implemented three different color quantization methods (ColorQ, Median Cut, K-Means++) and added a process button to allow settings to be changed prior to creating the output picture Optimizations - everything is FAST! K-Means+++ optimization reduces 50 iterations to well under 10 seconds for most images and allows full optimization to Epsilon 0 Palette Adjustment - can adjust any palette color and maintain current drawing OR redraw to use the optimized palette but clicking on the color in the palette or on the image itself Save BMP Option - allows you to further edit the bitmap and then reprocess. If input image is 16 colors and 160x200 you get perfect replication on output image Transparency - the upper left pixel is always set to color index 0, you can also hold ALT and click on the image to set the transparency (index 0) color I would really love to see some output image captures here if at all possible. I don't use Facebook so I can't get to the "real" Aquarius+ main forum. Thanks, Chris APImageWorks_V1.1.7z Quote Link to comment Share on other sites More sharing options...
chjmartin2 Posted September 19 Author Share Posted September 19 Hi, Here is a slideshow that I pieced together using Image Works and some demo code included with Aquarius+. Sean H wrote the original code. I got help from Curtis K on the additional code. It is just a slide show, but it used Palette manipulation to transition between images. It also pulls the artwork info from a file on the SD card. Lastly, it uses the Bitmap manipulation commands in plusBASIC. FINEART.7z Quote Link to comment Share on other sites More sharing options...
Trixter Posted September 19 Share Posted September 19 These look fantastic. I'd love to see how you implemented k-means++ and bayer dithering if you release the code someday. Quote Link to comment Share on other sites More sharing options...
chjmartin2 Posted September 19 Author Share Posted September 19 2 hours ago, Trixter said: These look fantastic. I'd love to see how you implemented k-means++ and bayer dithering if you release the code someday. I'll send you the specific code for both. It's in Freebasic but pretty easy to follow. They are much easier than I expected them to be. Not sure I am doing Bayer perfectly - really it is just an addition/subtraction matrix but it works. Quote Link to comment Share on other sites More sharing options...
chjmartin2 Posted September 20 Author Share Posted September 20 22 hours ago, Trixter said: These look fantastic. I'd love to see how you implemented k-means++ and bayer dithering if you release the code someday. Here are the relevant bits of code for Bayer: Dim imagein(159,199,3) 'Image array, x,y,c where c=1 is red, C=2 is green, c=3 is blue out of 255 Dim BayerMatrix(3, 3) As Single = _ '4x4 Ordered Dither Bayer Matrix {{0 / 15, 8 / 15, 2 / 15, 10 / 15}, _ {12 / 15, 4 / 15, 14 / 15, 6 / 15}, _ {3 / 15, 11 / 15, 1 / 15, 9 / 15}, _ {15 / 15, 7 / 15, 13 / 15, 5 / 15}} Pattern = frmMain.pattern.CheckState ' Checks GUI Control to see if Bayer is clicked or not bayerstrength = val(frmMain.BayerValue.Text)/100 ' Checks GUI Control for the BayerValue 0 to 100 and divides Dim scale As Double = -0.5 ' Used to center the bayer differences Dim Threshold As Double = 24 * BayerStrength 'BayerStrength ' Sets Bayer Threshold, experimented to find value of 24 ' Apply pattern, simply iterates through image. Magic line is where you add the bayer matrix using mod 4 to determine matrix ' position reducing it by the threshold and then rounding to the closest multiple of 32 out of 255 ' It is not palette aware of the output 16 color palette when it does this, nor does it compare the gamut provided and adjust ' But the output is pretty pleasing I think If Pattern = 1 Then For y = 0 To 199 For x = 0 To 159 For c = 1 To 3 imagein(x, y, c) = Int((imagein(x, y, c) + (BayerMatrix(x Mod 4, y Mod 4) - scale) * Threshold) / 32) * 32 Next c Next x Next y End If 'Later on this image is further processed to nearest color in the selected palette which also allows you to additionally apply 'diffusion dither It is a code snippet, so can't be compiled but it shows the important/relevant bits. There is some tweaking of values that may not make it a pure bayer algorithm but for sure it is the standard 4x4 matrix. Some opportunities for enhancement would be to allow 2x2 or 8x8 or others but 4x4 seemed to foot the bill for reduction from 8 bits per channel down to 16 colors. Here are the relevant bits of code for K-Means++: ' I left out the variable Dimensions and describe each as they are used. Take note that I have used a fixed random seed ' technically the K-Means++ algorithm would allow for an initial random seed and for the probabilistic determination ' of distances between clusters. K-Means++ improved on K-Means which would simply use a set of random clusters ' by multiplying it by total distance you get a more spread out version. It works. An optimization might be to sort ' the color palette in some meaningful way to really ensure the colors are spread out. if frmMain.kmeans.checked then kmeans = 1 If kmeans = 1 Then ' Make the result deterministic by using a fixed seed for the random number generator Randomize 0 ' Select the first centroid randomly Dim startIndex As Integer = IIf(IsTransparent = 1, 2, 1) ' Start from 2 if transparent Dim randomIndex As Integer = Int(Rnd * Colcount) + 1 ' Select a random color that exists in the image For c As Integer = 1 To 3 ' Cluster is the array that stores the 16 output colors Cluster(2, c) = Colors(randomIndex, c) ' Colors is an array that stores all unique colors in the input image Next c ' Select the remaining centroids For k As Integer = startIndex To 16 Dim totalDist As Double = 0 Dim distances(Colcount) As Double ' Array that holds the distances to nearest centroid ' Calculate distance from each point to the nearest centroid by iterating through all colors in array Colors(j,c) For j = startIndex To Colcount ' Every color is evaluated Mindist = 9999999 For i As Integer = 1 To k - 1 coldist = sqr(sqd(Cluster(i, 1), Colors(j, 1)) _ 'sqr is square root, sqd is squared differences + sqd(Cluster(i, 2), Colors(j, 2)) _ + sqd(Cluster(i, 3), Colors(j, 3))) If coldist < Mindist Then Mindist = coldist End If Next i distances(j) = Mindist 'add the minimum distance totalDist += distances(j) ' we use TotalDist later Next j ' Select the next centroid with probability proportional to the distance Dim r As Double = Rnd * totalDist 'this randomly (from fixed seed) selects the next centroid 'weighted by the total distance Dim cumulativeDist As Double = 0 For j = startIndex To Colcount cumulativeDist += distances(j) If cumulativeDist >= r Then For c As Integer = 1 To 3 Cluster(k, c) = Colors(j, c) Next c Exit For End If Next j Next k Do 'Now we are in the loop iteration += 1 'Iteration Counter change = 0 'Set Change tracker from last loop to 0 ' Clear new cluster sums For k As Integer = startIndex To 16 ' zero out an array the holds newly calculated clusters For c As Integer = 1 To 3 newCluster(k, c) = 0 Next c count(k) = 0 Next k ' Assign each color to the closest cluster For j = startIndex To Colcount ' For the Clusters calculated, find closest and assign Mindist = 9999999 mink = 1 For k As Integer = 1 To 16 coldist = sqr(sqd(Cluster(k, 1), Colors(j, 1)) _ + sqd(Cluster(k, 2), Colors(j, 2)) _ + sqd(Cluster(k, 3), Colors(j, 3))) If coldist < Mindist Then Mindist = coldist mink = k End If Next k ' Add this color to the corresponding cluster sum For c As Integer = 1 To 3 newCluster(mink, c) += Colors(j, c) Next c count(mink) += 1 Next j ' Update clusters with the new centroids ' This is the magic, it recenters the clusters to the newly assigned colors to that cluster ' It also tracks the amount of change by adding the absolute value of the difference of the old cluster color ' To the new one, if this change is zero then no further "optimization" is possible For k As Integer = startIndex To 16 If count(k) > 0 Then For c As Integer = 1 To 3 Dim newValue As Integer = newCluster(k, c) / count(k) change += Abs(newValue - Cluster(k, c)) Cluster(k, c) = newValue Next c End If Next k ' Update status bar with iteration number and change value Dim tout As String = "Iteration: " + Str(iteration) + ", Epsilon: " + Str(change) frmMain.StatusBar.Text = tout 'Epsilon is set really low as we can get to 0 in less than 50 iterations Loop While (change > epsilon) And (iteration < maxIterations) Happy to answer any questions if I can. Code is in Freebasic but pretty easy to translate elsewhere. Thanks, Chris Quote Link to comment Share on other sites More sharing options...
Recommended Posts
Join the conversation
You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.