Image manipulation to try to draw with colors that do not exist there
Close-Up Photography of Tabby Cat · Free Stock Photo
To see other works based on my code is my pleasure. And my honor.
Description of this image manipulation code.
It's a creative coding image manipulation code made with the 'Processing'.
I tried to draw an image without the color in the original image.
I did not use primary color like RGB nor CMY, I used a +-45 degree phase difference color from the original color.
You can enjoy these results in 3 or 4 meters distance.
The 'Processing' example code.
Please feel free to use this Processing example code under the terms of the GPL.To see other works based on my code is my pleasure. And my honor.
/** * DoMewno. * Draw original color image WITHOUT original color. * run : processing-java --force --sketch=/path/to/DoMewno/ --run "image path" * * @author @deconbatch * @version 0.1 * Processing 3.2.1 * 2019.03.21 */ /** * main */ void setup() { size(1080, 1080); colorMode(HSB, 360.0, 100.0, 100.0, 100.0); // rectMode(CENTER); smooth(); noLoop(); noStroke(); } void draw() { int caseWidth = 30; int baseCanvas = width - caseWidth * 2; // I brought domino pattern parameters in class. DominoParams bp = new BackgroundParams(); DominoParams ep = new EdgeParams(); ImageLoader imgLoader = new ImageLoader(baseCanvas); PImage img = imgLoader.load(); // edge detection int edgeAry[][] = detectEdge(img); translate((width - img.width) / 2, (height - img.height) / 2); background(0.0, 0.0, 90.0, 100.0); // draw domino pattern putDominos(bp, img, edgeAry); putDominos(ep, img, edgeAry); casing(caseWidth, img.width, img.height); saveFrame("frames/0001.png"); exit(); } /** * putDominos : draw pattern like domino. * @param _dp : domino pattern parameters class. * @param _img : origimal photo image. * @param _edge : detented edge information. */ private void putDominos(DominoParams _dp, PImage _img, int[][] _edge) { int initDiv = _dp.initDiv(); float colorDiff = 45.0; int halfDiv = round(initDiv * 0.5); for (int xInit = 0; xInit < _img.width; xInit += initDiv) { for (int yInit = 0; yInit < _img.height; yInit += initDiv) { if (_dp.isTarget(_edge, xInit, yInit)) { // I want to draw diffrent color like this // --------- // | - | + | // --------- // | + | - | // --------- int xW = constrain(xInit, 0, _img.width - 1); int xE = constrain(xInit + halfDiv, 0, _img.width - 1); int yN = constrain(yInit, 0, _img.height - 1); int yS = constrain(yInit + halfDiv, 0, _img.height - 1); paintDiffCol(_img, xW, yN, halfDiv, -colorDiff); // West-North paintDiffCol(_img, xW, yS, halfDiv, +colorDiff); // West-South paintDiffCol(_img, xE, yN, halfDiv, +colorDiff); // East-North paintDiffCol(_img, xE, yS, halfDiv, -colorDiff); // East-South } } } } /** * paintDiffCol : paint rect and ellipse with different color. * @param _img : origimal photo image. * @param _xCorner, _yCorner : West-North point of rect to draw. * @param _size : width and height of rect to draw. * @param _colorDiff : phase differenct of color in HSB(360). */ private void paintDiffCol(PImage _img, int _xCorner, int _yCorner, int _size, float _colorDiff) { int xTo = constrain(_xCorner + _size, 0, _img.width - 1); int yTo = constrain(_yCorner + _size, 0, _img.height - 1); // using RGB to calculate the average hue colorMode(RGB); int sumCnt = 0; float sumRed = 0.0; float sumGre = 0.0; float sumBlu = 0.0; for (int sumX = _xCorner; sumX < xTo; ++sumX) { for (int sumY = _yCorner; sumY < yTo; ++sumY) { color pix = _img.pixels[sumY * _img.width + sumX]; sumRed += red(pix); sumGre += green(pix); sumBlu += blue(pix); ++sumCnt; } } float eHue = hue(color(sumRed / sumCnt, sumGre / sumCnt, sumBlu / sumCnt)); // using HSB to calculate the average saturation and brightness // Q. Why I do not keep using RGB? // A. I need to calculate _colorDiff different hue value. And I don't know how to do it with RGB. colorMode(HSB, 360.0, 100.0, 100.0, 100.0); sumCnt = 0; float sumSat = 0.0; float sumBri = 0.0; for (int sumX = _xCorner; sumX < xTo; ++sumX) { for (int sumY = _yCorner; sumY < yTo; ++sumY) { color pix = _img.pixels[sumY * _img.width + sumX]; sumSat += saturation(pix); sumBri += brightness(pix); ++sumCnt; } } float eSat = sumSat * 1.1 / sumCnt; float eBri = sumBri / sumCnt; float eAlp = 100.0; fill((eHue + 360 + _colorDiff) % 360.0, eSat, eBri, eAlp); rect(_xCorner, _yCorner, _size, _size); fill((eHue + 360 - _colorDiff) % 360.0, eSat, eBri, eAlp); ellipse(_xCorner + _size * 0.5, _yCorner + _size * 0.5, _size * 0.65, _size * 0.65); } /** * casing : draw fancy casing */ private void casing(int _casing, float _w, float _h) { fill(0.0, 0.0, 0.0, 0.0); strokeWeight(_casing + 4.0); stroke(0.0, 0.0, 30.0, 100.0); rect(-_casing * 0.5, -_casing * 0.5, _w + _casing, _h + _casing); strokeWeight(_casing); stroke(0.0, 0.0, 100.0, 100.0); rect(-_casing * 0.5, -_casing * 0.5, _w + _casing, _h + _casing); noStroke(); noFill(); } /** * detectEdge : detect edge of photo image. * @param _img : detect edge of thid image. * @return int[x][y] : 2 dimmension array. it holds 0 or 1, 1 = edge */ private int[][] detectEdge(PImage _img) { int edgeAry[][] = new int[_img.width][_img.height]; for (int idxW = 0; idxW < _img.width; ++idxW) { for (int idxH = 0; idxH < _img.height; ++idxH) { edgeAry[idxW][idxH] = 0; } } _img.loadPixels(); for (int idxW = 1; idxW < _img.width - 1; ++idxW) { for (int idxH = 1; idxH < _img.height - 1; ++idxH) { int pixIndex = idxH * _img.width + idxW; // saturation difference float satCenter = saturation(_img.pixels[pixIndex]); float satNorth = saturation(_img.pixels[pixIndex - _img.width]); float satWest = saturation(_img.pixels[pixIndex - 1]); float satEast = saturation(_img.pixels[pixIndex + 1]); float satSouth = saturation(_img.pixels[pixIndex + _img.width]); float lapSat = pow( - satCenter * 4.0 + satNorth + satWest + satSouth + satEast , 2); // brightness difference float briCenter = brightness(_img.pixels[pixIndex]); float briNorth = brightness(_img.pixels[pixIndex - _img.width]); float briWest = brightness(_img.pixels[pixIndex - 1]); float briEast = brightness(_img.pixels[pixIndex + 1]); float briSouth = brightness(_img.pixels[pixIndex + _img.width]); float lapBri = pow( - briCenter * 4.0 + briNorth + briWest + briSouth + briEast , 2); // hue difference float hueCenter = hue(_img.pixels[pixIndex]); float hueNorth = hue(_img.pixels[pixIndex - _img.width]); float hueWest = hue(_img.pixels[pixIndex - 1]); float hueEast = hue(_img.pixels[pixIndex + 1]); float hueSouth = hue(_img.pixels[pixIndex + _img.width]); float lapHue = pow( - hueCenter * 4.0 + hueNorth + hueWest + hueSouth + hueEast , 2); // bright and saturation difference if ( brightness(_img.pixels[pixIndex]) > 30.0 && lapSat > 20.0 ) edgeAry[idxW][idxH] = 1; // bright and some saturation and hue difference if ( brightness(_img.pixels[pixIndex]) > 30.0 && saturation(_img.pixels[pixIndex]) > 10.0 && lapHue > 100.0 ) edgeAry[idxW][idxH] = 1; // just brightness difference if (lapBri > 100.0) edgeAry[idxW][idxH] = 1; } } return edgeAry; } /** * ImageLoader : load and resize image */ public class ImageLoader { PImage imgInit; String imgPass; ImageLoader(int baseCanvas) { if (args == null) { // you can use your photo in ./data/your_image.jpg imgPass = "your_image.jpg"; } else { // args[0] must be image path imgPass = args[0]; } imgInit = loadImage(imgPass); float rateSize = baseCanvas * 1.0 / max(imgInit.width, imgInit.height); imgInit.resize(floor(imgInit.width * rateSize), floor(imgInit.height * rateSize)); println(int(imgInit.width)); // Image width println(int(imgInit.height)); // Image height } /** * load : return loaded image */ public PImage load() { return imgInit; } } /** * DominoParams : holding domino pattern parameters. */ interface DominoParams { /** * isTarget : is this point(x, y) drawing target? * @return true : draw target */ Boolean isTarget(int _points[][], int _x, int _y); /** * just returns parameter value */ int initDiv(); } public class BackgroundParams implements DominoParams { public Boolean isTarget(int _points[][], int _x, int _y) { // every point return true; } public int initDiv() { return 40; } } public class EdgeParams implements DominoParams { public Boolean isTarget(int _points[][], int _x, int _y) { // only edge is target if (_points[_x][_y] == 1) { return true; } return false; } public int initDiv() { return 20; } } /* Copyright (C) 2019- deconbatch This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses/> */
Yet another example result of this image manipulation.