I have a few hundred photos. Each photograph is one object. And with each photo repeat the same steps:
Open, select the area; crop, resize, fix brightness, save.
My attempt to automate the process: write a script and hang it on a hotkey.
(define (script-fu-cut800 inText inFont inFontSize inTextColor)
; get the coordinates of allocation
(gimp-image-get-selection (image))
(let * (
(original-left (car (????)))
(original-top (car (????)))
(original-width (car (gimp-image-width image)))
(original-height (car (gimp-image-height image)))
(new-width (- original-width (+ right left)))
(new-height (- original-height (+ top bottom)))
)
; crop the selected image
(gimp-image-crop image new-width new-height left top)
; resize to 800 * 800
(gimp-image-resize image 800 800 0 0)
; open dialogue correction levels
(?????)
; save as JPG 80% compression of the same name
(file-jpeg-save ????)
))
Related
I'm new to Script-Fu and am trying to write a script which takes in a layer name and color and recolors all black pixels in that layer the specified color. My code is below. I register it using script-fu-register and calling it from within the graphic interface. When I try to run it, I get the illegal function error. It seems to be something related to gimp-image-get-layer-by-name (when I comment out that part, the function that is supposed to save the file as a png runs fine). Would be very grateful for any suggestions!
(define (script-fu-recolor-layer image color layername imgoutname)
(gimp-image-undo-group-start image)
(gimp-selection-none image)
(gimp-context-set-foreground color)
(gimp-message (number->string (car (gimp-image-get-layer-by-name image layername))))
(let*
(
(activelayer (car (gimp-image-get-layer-by-name image layername)))
)
(
(gimp-image-select-color image 0 activelayer '(0 0 0))
(gimp-edit-bucket-fill activelayer FG-BUCKET-FILL NORMAL-MODE 100 0 0 0 0)
(gimp-item-set-visible activelayer 1)
)
)
; source: https://stackoverflow.com/questions/49922377/how-to-export-flattened-image-with-gimp-script-fu
(let* (
(duplicateImg (car (gimp-image-duplicate image) ) )
)
(let* (
(flatLayer (car (gimp-image-flatten duplicateImg) ) )
)
(
(file-png-save 1 duplicateImg flatLayer imgoutname imgoutname 1 0 0 0 0 0 0)
)
)
)
(gimp-image-undo-group-end image)
(gimp-displays-flush)
)
So for whatever reason the code above throws an error but if I declare the active layer variable using "define" it runs fine:
(define activelayer (car (gimp-image-get-layer-by-name image layername)))
Instead of assigning it within the let* clause. So changing this worked for me -- but I still don't understand why it didn't work with let*.
I have many png files like this:
I want to slice the image into 48 (=6x8) small image files for the 48 cells separated by the table borders. That is, I would like to have files img11.png, ..., img68.png, where img11.png contains the (1,1) "1.4x4x8" cell, img12.png the (1,2) "M/T" cell, img13.png the "550,000" cell, ..., img68.png the bottom right "641,500" cell.
I want to do it because I thought it would improve the performance of tesseract, which is not satisfactory because many of my image files have much poorer quality than shown above. Also, margins and sizes are diverse, and some images contain non-English characters and images.
Would there be software packages to detect the table borders and slice the image into m x n images? I am new in this area. I have read How to find table like structure in image but it's way beyond my ability. I am willing to learn, though.
Thanks for your help.
I'm using R. Bilal's suggestion (thanks) led me to the following.
Step 1: Convert the image to grayscale.
library(magick)
x <- image_read('https://i.stack.imgur.com/plBvs.png')
y <- image_convert(x, colorspace='Gray')
a <- as.integer(y[[1]])[,,1]
Step 2: Convert "dark" to 1 and "light" to 0.
w <- ifelse(a>190, 0, 1) # adjust 190
Step 3: Detect the horizontal and vertical lines.
ypos <- which(rowMeans(w) > .95) # adjust .95
xpos <- which(colMeans(w) > .95) # adjust .95
Step 4: Crop the original image (x).
xpos <- c(0,xpos, ncol(a))
ypos <- c(0,ypos, nrow(a))
outdir <- "cropped"
dir.create(outdir)
m <- 0
for (i in 1:(length(ypos)-1)) {
dy <- ypos[i+1]-ypos[i]
n <- 0
if (dy < 16) next # skip if too short
m <- m+1
for (j in 1:(length(xpos)-1)) {
dx <- xpos[j+1]-xpos[j]
if (dx < 16) next # skip if too narrow
n <- n+1
geom <- sprintf("%dx%d+%d+%d", dx, dy, xpos[j], ypos[i])
# cat(sprintf('%2d %2d: %s\n', m, n, geom))
cropped <- image_crop(x, geom)
outfile <- file.path(outdir, sprintf('%02d_%02d.png', m, n))
image_write(cropped, outfile, format="png")
}
}
The cropped (1,1) image is .
I read about Concat layer on Caffe website. However, I don't know if my understanding of it is right.
Let's say that as an input I have two layers that can be described as W1 x H1 x D1 and W2 x H2 x D2, where W is the width, H is height and D is depth.
Thus, as I understand with Axis set to 0 output will be (W1 + W2) x (H1 + H2) x D, where D = D1 = D2.
With Axis set to 1 output will be W x H x (D1 + D2), where H = H1 = H2 and W = W1 = W2.
Is my understanding correct? If no I would be grateful for an explanation.
I'm afraid you are a bit off...
Look at this caffe.help.
Usually, data in caffe is stored in 4D "blobs": BxCxHxW (that is, batch size by channel/feature/depth by height by width).
Now if you have two blobs B1xC1xH1xW1 and B2xC2xH2xW2 you can concatenate them along axis: 1 (along channel dimension) to form an output blob with C=C1+C2. This is only possible iff B1==B2 and H1==H2 and W1==W2, resulting with B1x(C1+C2)xH1xW1
I want to create an image like notebooke paper,
and I thought it is easy if the section of drawing lines
is automated.
In order to make it, I decided to use gimp's function named
'gimp-rect-select' and specify the small height value.
I google-searched and wrote a scheme file,
but when I ran it from gimp's Script-Fu menu,
gimp showed me the message as below.
Error while executing FU01-multi-rect-select:
Error: ( : 1)
Invalid number of arguments for gimp-rect-select
(expected 8 but received 9)
I would like you to see my first script-fu and
point out where something wrong is involved.
To me, my custom function is defined so that
it has 8 parameters, not 9.
The folloing is my code
(define (FU01-multi-rect-select
image
drawable
x1
y1
w
h
p-offset
p-repeat
)
;definition of variables
(let*
(
(X nil)
(Y nil)
(width nil)
(height nil)
(offset nil)
(repeat nil)
;are they below necessary?
(theLayer nil)
(theImage nil)
)
;(gimp-context-push )
(gimp-image-undo-group-start image)
;(set! X (string->number x1))
;(set! Y (string->number y1))
;(set! width (string->number w))
;(set! height (string->number h))
;(set! offset (string->number p-offset))
;(set! repeat (string->number p-repeat))
(set! X x1)
(set! Y y1)
(set! width w)
(set! height h)
(set! offset p-offset)
(set! repeat p-repeat)
(gimp-image-set-active-layer image drawable)
(set! theLayer
(car (gimp-image-get-active-layer image) )
)
; select rectangle and after that,
; add it to current selection
; multiple times that is specified with 'repeat'
(while (> repeat 0)
(gimp-rect-select image X Y width height
CHANNEL-OP-ADD FALSE 0 0)
(set! Y (+ Y height offset))
(set! repeat (- repeat 1))
)
(gimp-image-undo-group-end image)
) ; end of let sentences
)
(script-fu-register "FU01-multi-rect-select"
"<Image>/Script-Fu/Select/multi rect select"
"add a rect selection to current selection multiple times\
each time a rect is selected it is moved\
in y axis by the value of offset"
"Masaaki Fujioka"
"copy right 2014 Masaaki Fujioka"
"August 3 2014"
"*"
SF-IMAGE "SF-IMAGE" 0
SF-DRAWABLE "SF-DRAWABLE" 0
SF-VALUE "start x" "0"
SF-VALUE "start y" "0"
SF-VALUE "width" "0"
SF-VALUE "height" "0"
SF-VALUE "offset" "0"
SF-VALUE "repeat" "0"
)
Just like the error message says, you have one extra parameter to the gimp-rect-select call - if you check the specs for the call on the procedure browser, after the "mode" parameter there should be one boolean to tell whether you want to use feathering, and another number to tell the feathering amount. You are passing two integers instead of just one number needed.
Also, pay attention that this call is marked as "deprecated" - which means that although it still works in gimp-2.8, for a series of reason, you should be calling gimp-image-select-rectangle instead of this. (note that the parameters for that call differ).
I'm experimenting with the ImageTransformation function to try to make anamorphic versions of images, but with limited progress so far. I'm aiming for the results you get using the image reflected in a cylindrical mirror, where the image curves around the central mirror for about 270 degrees. The wikipedia article has a couple of neat examples (and I borrowed Holbein's skull from them too).
i = Import["../Desktop/Holbein_Skull.jpg"];
i = ImageResize[i, 120]
f[x_, y_] := {(2 (y - 0.3) Cos [1.5 x]), (2 (y - 0.3) Sin [1.5 x])};
ImageTransformation[i, f[#[[1]], #[[2]]] &, Padding -> White]
But I can't persuade Mathematica to show me the entire image, or to bend it correctly. The anamorphic image should wrap right round the mirror placed "inside" the centre of the image, but it won't. I found suitable values for constants by putting it inside a manipulate (and turning the resolution down :). I'm using the formula:
x1 = a(y + b) cos(kx)
y1 = a(y + b) sin(kx)
Any help producing a better result would be greatly appreciated!
In ImageTransformation[f,img], the function f is such that a point {x,y} in the resulting image corresponds to f[{x,y}] in img. Since the resulting image is basically the polar transformation of img, f should be the inverse polar transformation, so you could do something like
anamorphic[img_, angle_: 270 Degree] :=
Module[{dim = ImageDimensions[img], rInner = 1, rOuter},
rOuter = rInner (1 + angle dim[[2]]/dim[[1]]);
ImageTransformation[img,
Function[{pt}, {ArcTan[-#2, #1] & ## pt, Norm[pt]}],
DataRange -> {{-angle/2, angle/2}, {rInner, rOuter}},
PlotRange -> {{-rOuter, rOuter}, {-rOuter, rOuter}},
Padding -> White
]
]
The resulting image looks something like
anamorphic[ExampleData[{"TestImage", "Lena"}]]
Note that you can a similar result with ParametricPlot and TextureCoordinateFunction, e.g.
anamorphic2[img_Image, angle_: 270 Degree] :=
Module[{rInner = 1,rOuter},
rOuter = rInner (1 + angle #2/#1 & ## ImageDimensions[img]);
ParametricPlot[{r Sin[t], -r Cos[t]}, {t, -angle/2, angle/2},
{r, rInner, rOuter},
TextureCoordinateFunction -> ({#3, #4} &),
PlotStyle -> {Opacity[1], Texture[img]},
Mesh -> None, Axes -> False,
BoundaryStyle -> None,
Frame -> False
]
]
anamorphic2[ExampleData[{"TestImage", "Lena"}]]
Edit
In answer to Mr.Wizard's question, if you don't have access to ImageTransformation or Texture you could transform the image data by hand by doing something like
anamorph3[img_, angle_: 270 Degree, imgWidth_: 512] :=
Module[{data, f, matrix, dim, rOuter, rInner = 1.},
dim = ImageDimensions[img];
rOuter = rInner (1 + angle #2/#1 & ## dim);
data = Table[
ListInterpolation[#[[All, All, i]],
{{rOuter, rInner}, {-angle/2, angle/2}}], {i, 3}] &#ImageData[img];
f[i_, j_] := If[Abs[j] <= angle/2 && rInner <= i <= rOuter,
Through[data[i, j]], {1., 1., 1.}];
Image#Table[f[Sqrt[i^2 + j^2], ArcTan[i, -j]],
{i, -rOuter, rOuter, 2 rOuter/(imgWidth - 1)},
{j, -rOuter, rOuter, 2 rOuter/(imgWidth - 1)}]]
Note that this assumes that img has three channels. If the image has fewer or more channels, you need to adapt the code.