//ProjectGray returns a greyscale sinogram (or radon projection) of img // N(default: 360): number of image rotation on which a projection will be done // A naive simplistic approach // Sinograms looks like this : // θ1 θ2 θ3...θN // | | | | // | | | | func ProjectGray(src image.Image, N int) (*image.Gray, error) { if N == 0 { N = 360 } step := 180.0 / float64(N) size := src.Bounds().Size() overX := int(float64(size.X) * 1.1) overY := int(float64(size.Y) * 1.1) var img image.Image = image.NewGray(image.Rect(0, 0, size.X+overX, size.Y+overY)) img = imaging.Overlay(img, src, image.Pt(overX/2, overY/2), 1) size = img.Bounds().Size() D := max(size.X, size.Y) out := image.NewGray(image.Rect(0, 0, N, D)) // for each given angle θ for n := 0; n < N; n++ { θ := float64(n) * step draw := image.NewRGBA(image.Rect(0, 0, img.Bounds().Dy(), img.Bounds().Dx())) //have a duplicate img rotated by θ err := graphics.Rotate(draw, img, &graphics.RotateOptions{Angle: manipulator.Rad(θ)}) if err != nil { return out, err } sinogram := make([]float64, size.X) // get column average profile for y := 0; y < size.Y; y++ { for x := 0; x < size.X; x++ { greyColor, _ := color.GrayModel.Convert(draw.At(x, y)).(color.Gray) sinogram[x] = sinogram[x] + float64(greyColor.Y) } } //Set out line with sinogram for d := 0; d < D; d++ { out.Set(n, d, color.Gray{uint8(sinogram[d] / float64(size.Y))}) } } return out, nil }
func loadImageRotated(image_name string, angle float64) (*sdl.Surface, error) { file, err := assets.Asset(image_name) if err != nil { return nil, err } i, _, err := image.Decode(bytes.NewReader(file)) if err != nil { return nil, err } dst := image.NewRGBA(i.Bounds()) err = graphics.Rotate(dst, i, &graphics.RotateOptions{ Angle: angle * tau}) if err != nil { return nil, err } var buf bytes.Buffer err = png.Encode(&buf, dst) if err != nil { return nil, err } b := buf.Bytes() return img.Load_RW(sdl.RWFromMem(unsafe.Pointer(&b[0]), len(b)), 0) }
//BackProjectGray computes back projection of img // in Gray16 by performing an addition // of backprojection by line. // 16Gray avoids white noise. func BackProjectGray(img image.Gray) (*image.Gray16, error) { size := img.Bounds().Size() width := size.Y nbProj := size.X step := 180.0 / float64(nbProj) out := image.NewGray16(image.Rect(0, 0, width, width)) for X := 0; X < nbProj; X++ { //Extract a 1D-projection (one row Y of sinogram) line := img.SubImage(image.Rect(X, 0, X+1, width)).(*image.Gray) // 3- Do the backprojection and rotate accordingly wideLine := resize.Resize(uint(width), uint(width), line, resize.Lanczos3).(*image.Gray) θ := manipulator.Rad(float64(X)*step) + math.Pi/2 rotatedWideLine := image.NewGray(image.Rect(0, 0, width, width)) err := graphics.Rotate(rotatedWideLine, wideLine, &graphics.RotateOptions{Angle: θ}) if err != nil { return out, err } // 4- Add the rotated backprojection in the output image for x := 0; x < width; x++ { for y := 0; y < width; y++ { point := uint16(out.At(x, y).(color.Gray16).Y) + uint16(rotatedWideLine.At(x, y).(color.Gray).Y) out.Set(x, y, color.Gray16{uint16(point)}) } } } return out, nil }
func SnapshotRotated() (dst *image.RGBA, err error) { img, err := Snapshot() if err != nil { return } rotate := Rotation() options := &graphics.RotateOptions{math.Pi * float64(4-rotate) / 2.0} if rotate%2 != 0 { dst = image.NewRGBA(image.Rect(0, 0, img.Bounds().Dy(), img.Bounds().Dx())) } else { dst = image.NewRGBA(img.Bounds()) } err = graphics.Rotate(dst, img, options) if err != nil { return } return }
func flipImage(body []byte) []byte { // Is it an image? img, typ, err := image.Decode(bytes.NewReader(body)) if err != nil { return body } dst := image.NewRGBA(img.Bounds()) graphics.Rotate(dst, img, &graphics.RotateOptions{Angle: math.Pi}) var buf bytes.Buffer switch typ { case "png": err = png.Encode(&buf, dst) case "jpeg": err = jpeg.Encode(&buf, dst, nil) case "gif": err = gif.Encode(&buf, dst, nil) } if err != nil || buf.Len() == 0 { return body } body = buf.Bytes() return body }
func getImgBag(dir, filename string, angle Angle) *ImageBag { img, found := testImages[dir+filename] if !found { testImages[dir+filename] = new(ImageBag) testImages[dir+filename].Dir = dir testImages[dir+filename].Filename = filename testImages[dir+filename].Rotations = map[Angle]*ImageBag{} testImages[dir+filename].InitialiseFromFileInfo() img = testImages[dir+filename] } if angle != 0 { rotatedImage, found := img.Rotations[angle] if !found { draw := manipulator.CopyImage(img.Radon.Image) err := graphics.Rotate(draw, img.Radon.Image, &graphics.RotateOptions{Angle: float64(angle)}) if err != nil { panic(err) } rImg := ImageBag{ Dir: dir, Filename: filename, Angle: angle, ImageDigest: phash.ImageDigest{ Radon: radon.ImageDigest{ Image: draw, Format: img.Radon.Format}}} img.Rotations[angle] = &rImg return img.Rotations[angle] } return rotatedImage } return img }
func fireAndForgetHandleImages(filenames []string, fileData [][]byte, teamId, channelId, userId string) { go func() { dest := "teams/" + teamId + "/channels/" + channelId + "/users/" + userId + "/" for i, filename := range filenames { name := filename[:strings.LastIndex(filename, ".")] go func() { // Decode image bytes into Image object img, _, err := image.Decode(bytes.NewReader(fileData[i])) if err != nil { l4g.Error("Unable to decode image channelId=%v userId=%v filename=%v err=%v", channelId, userId, filename, err) return } width := img.Bounds().Dx() height := img.Bounds().Dy() // Get the image's orientation and ignore any errors since not all images will have orientation data orientation, _ := getImageOrientation(fileData[i]) // Create a temporary image that will be manipulated and then used to make the thumbnail and preview image var temp *image.RGBA switch orientation { case Upright, UprightMirrored, UpsideDown, UpsideDownMirrored: temp = image.NewRGBA(img.Bounds()) case RotatedCCW, RotatedCCWMirrored, RotatedCW, RotatedCWMirrored: bounds := img.Bounds() temp = image.NewRGBA(image.Rect(bounds.Min.Y, bounds.Min.X, bounds.Max.Y, bounds.Max.X)) width, height = height, width } // Draw a white background since JPEGs lack transparency draw.Draw(temp, temp.Bounds(), image.NewUniform(color.White), image.Point{}, draw.Src) // Copy the original image onto the temporary one while rotating it as necessary switch orientation { case UpsideDown, UpsideDownMirrored: // rotate 180 degrees err := graphics.Rotate(temp, img, &graphics.RotateOptions{Angle: math.Pi}) if err != nil { l4g.Error("Unable to rotate image") } case RotatedCW, RotatedCWMirrored: // rotate 90 degrees CCW graphics.Rotate(temp, img, &graphics.RotateOptions{Angle: 3 * math.Pi / 2}) if err != nil { l4g.Error("Unable to rotate image") } case RotatedCCW, RotatedCCWMirrored: // rotate 90 degrees CW graphics.Rotate(temp, img, &graphics.RotateOptions{Angle: math.Pi / 2}) if err != nil { l4g.Error("Unable to rotate image") } case Upright, UprightMirrored: draw.Draw(temp, temp.Bounds(), img, img.Bounds().Min, draw.Over) } img = temp // Create thumbnail go func() { thumbWidth := float64(utils.Cfg.ImageSettings.ThumbnailWidth) thumbHeight := float64(utils.Cfg.ImageSettings.ThumbnailHeight) imgWidth := float64(width) imgHeight := float64(height) var thumbnail image.Image if imgHeight < thumbHeight && imgWidth < thumbWidth { thumbnail = img } else if imgHeight/imgWidth < thumbHeight/thumbWidth { thumbnail = resize.Resize(0, utils.Cfg.ImageSettings.ThumbnailHeight, img, resize.Lanczos3) } else { thumbnail = resize.Resize(utils.Cfg.ImageSettings.ThumbnailWidth, 0, img, resize.Lanczos3) } buf := new(bytes.Buffer) err = jpeg.Encode(buf, thumbnail, &jpeg.Options{Quality: 90}) if err != nil { l4g.Error("Unable to encode image as jpeg channelId=%v userId=%v filename=%v err=%v", channelId, userId, filename, err) return } if err := writeFile(buf.Bytes(), dest+name+"_thumb.jpg"); err != nil { l4g.Error("Unable to upload thumbnail channelId=%v userId=%v filename=%v err=%v", channelId, userId, filename, err) return } }() // Create preview go func() { var preview image.Image if width > int(utils.Cfg.ImageSettings.PreviewWidth) { preview = resize.Resize(utils.Cfg.ImageSettings.PreviewWidth, utils.Cfg.ImageSettings.PreviewHeight, img, resize.Lanczos3) } else { preview = img } buf := new(bytes.Buffer) err = jpeg.Encode(buf, preview, &jpeg.Options{Quality: 90}) if err != nil { l4g.Error("Unable to encode image as preview jpg channelId=%v userId=%v filename=%v err=%v", channelId, userId, filename, err) return } if err := writeFile(buf.Bytes(), dest+name+"_preview.jpg"); err != nil { l4g.Error("Unable to upload preview channelId=%v userId=%v filename=%v err=%v", channelId, userId, filename, err) return } }() }() } }() }
// rotate rotates the Painting's image counter-clockwise by angle in degrees. // angle modulo 360 must be one of 0, 90, 180, 270. func (p *Painting) rotate(c appengine.Context, angle int) error { switch math.Abs(float64(angle % 360)) { case 0, 90, 180, 270: break default: return errors.New(fmt.Sprintf("painting: Unsupported angle %f.", angle)) } if p.Image == (Image{}) { return nil } // Read the image from the blobstore. r := blobstore.NewReader(c, p.Image.BlobKey) src, _, err := image.Decode(r) if err != nil { return err } // Create the rotated image. srcRect := src.Bounds() var dstRect image.Rectangle if angle == 0 || angle == 180 { dstRect = srcRect } else { dstRect = image.Rect(0, 0, srcRect.Dy(), srcRect.Dx()) } dst := image.NewNRGBA(dstRect) err = graphics.Rotate(dst, src, &graphics.RotateOptions{ Angle: float64(angle%360) * math.Pi / 180, }) if err != nil { return err } // Create a new blob for the rotated image. w, err := blobstore.Create(c, "image/png") if err != nil { return err } err = png.Encode(w, dst) if err != nil { return err } err = w.Close() if err != nil { return err } // Delete the old blob. deleteBlobLater.Call(c, p.Image.BlobKey) // Update the image metadata. p.Image.BlobKey, err = w.Key() if err != nil { return err } p.Image.Width = dstRect.Dx() p.Image.Height = dstRect.Dy() u, err := aeimage.ServingURL(c, p.Image.BlobKey, nil) if err != nil { return err } p.Image.URL = u.String() err = p.Save(c) if err != nil { return err } return nil }
func (ig *ImageGraphics) Text(x, y int, t string, align string, rot int, f chart.Font) { if len(align) == 1 { align = "c" + align } textImage := ig.textBox(t, f) bounds := textImage.Bounds() w, h := bounds.Dx(), bounds.Dy() var centerX, centerY int if rot != 0 { alpha := float64(rot) / 180 * math.Pi cos := math.Cos(alpha) sin := math.Sin(alpha) hs, hc := float64(h)*sin, float64(h)*cos ws, wc := float64(w)*sin, float64(w)*cos W := int(math.Ceil(hs + wc)) H := int(math.Ceil(hc + ws)) rotated := image.NewAlpha(image.Rect(0, 0, W, H)) graphics.Rotate(rotated, textImage, &graphics.RotateOptions{-alpha}) textImage = rotated centerX, centerY = W/2, H/2 switch align { case "bl": centerX, centerY = int(hs), H case "bc": centerX, centerY = W-int(wc/2), int(ws/2) case "br": centerX, centerY = W, int(hc) case "tl": centerX, centerY = 0, H-int(hc) case "tc": centerX, centerY = int(ws/2), H-int(ws/2) case "tr": centerX, centerY = W-int(hs), 0 case "cl": centerX, centerY = int(hs/2), H-int(hc/2) case "cr": centerX, centerY = W-int(hs/2), int(hc/2) } } else { centerX, centerY = w/2, h/2 switch align[0] { case 'b': centerY = h case 't': centerY = 0 } switch align[1] { case 'l': centerX = 0 case 'r': centerX = w } } bounds = textImage.Bounds() w, h = bounds.Dx(), bounds.Dy() x -= centerX y -= centerY x += ig.x0 y += ig.y0 var col color.Color if f.Color != nil { col = f.Color } else { col = color.NRGBA{0, 0, 0, 0xff} } tcol := image.NewUniform(col) draw.DrawMask(ig.Image, image.Rect(x, y, x+w, y+h), tcol, image.ZP, textImage, textImage.Bounds().Min, draw.Over) }
func (ig *ImageGraphics) Text(x, y int, t string, align string, rot int, f chart.Font) { if len(align) == 1 { align = "c" + align } // fw, fh, _ := ig.FontMetrics(f) //fmt.Printf("Text '%s' at (%d,%d) %s\n", t, x,y, align) // TODO: handle rot size := ig.relFontsizeToPixel(f.Size) textImage := ig.textBox(t, size) bounds := textImage.Bounds() w, h := bounds.Dx(), bounds.Dy() var centerX, centerY int if rot != 0 { alpha := float64(rot) / 180 * math.Pi cos := math.Cos(alpha) sin := math.Sin(alpha) hs, hc := float64(h)*sin, float64(h)*cos ws, wc := float64(w)*sin, float64(w)*cos W := int(math.Ceil(hs + wc)) H := int(math.Ceil(hc + ws)) rotated := image.NewAlpha(image.Rect(0, 0, W, H)) graphics.Rotate(rotated, textImage, &graphics.RotateOptions{-alpha}) textImage = rotated centerX, centerY = W/2, H/2 switch align { case "bl": centerX, centerY = int(hs), H case "bc": centerX, centerY = W-int(wc/2), int(ws/2) case "br": centerX, centerY = W, int(hc) case "tl": centerX, centerY = 0, H-int(hc) case "tc": centerX, centerY = int(ws/2), H-int(ws/2) case "tr": centerX, centerY = W-int(hs), 0 case "cl": centerX, centerY = int(hs/2), H-int(hc/2) case "cr": centerX, centerY = W-int(hs/2), int(hc/2) } } else { centerX, centerY = w/2, h/2 switch align[0] { case 'b': centerY = h case 't': centerY = 0 } switch align[1] { case 'l': centerX = 0 case 'r': centerX = w } } bounds = textImage.Bounds() w, h = bounds.Dx(), bounds.Dy() x -= centerX y -= centerY x += ig.x0 y += ig.y0 col := "#000000" if f.Color != "" { col = f.Color } r, g, b := chart.Color2rgb(col) tcol := image.NewUniform(color.RGBA{uint8(r), uint8(g), uint8(b), 255}) draw.DrawMask(ig.Image, image.Rect(x, y, x+w, y+h), tcol, image.ZP, textImage, textImage.Bounds().Min, draw.Over) }
func (c Application) PostUpload(name string) rev.Result { c.Validation.Required(name) if c.Validation.HasErrors() { c.FlashParams() c.Validation.Keep() return c.Redirect(Application.Upload) } photoDir := path.Join(PHOTO_DIRECTORY, name) thumbDir := path.Join(PHOTO_DIRECTORY, "thumbs", name) err := os.MkdirAll(photoDir, 0777) if err != nil { c.FlashParams() c.Flash.Error("Error making directory:", err) return c.Redirect(Application.Upload) } err = os.MkdirAll(thumbDir, 0777) if err != nil { c.FlashParams() c.Flash.Error("Error making directory:", err) return c.Redirect(Application.Upload) } photos := c.Params.Files["photos[]"] for _, photoFileHeader := range photos { // Open the photo. input, err := photoFileHeader.Open() if err != nil { c.FlashParams() c.Flash.Error("Error opening photo:", err) return c.Redirect(Application.Upload) } photoBytes, err := ioutil.ReadAll(input) if err != nil || len(photoBytes) == 0 { rev.ERROR.Println("Failed to read image:", err) continue } input.Close() // Decode the photo. photoImage, format, err := image.Decode(bytes.NewReader(photoBytes)) if err != nil { rev.ERROR.Println("Failed to decode image:", err) continue } // Decode the EXIF data x, err := exif.Decode(bytes.NewReader(photoBytes)) if err != nil { rev.ERROR.Println("Failed to decode image exif:", err) continue } var orientation int = 1 if orientationTag, err := x.Get(exif.Orientation); err == nil { orientation = int(orientationTag.Int(0)) } photoName := path.Base(photoFileHeader.Filename) // Create a thumbnail thumbnail := image.NewRGBA(image.Rect(0, 0, 256, 256)) err = graphics.Thumbnail(thumbnail, photoImage) if err != nil { rev.ERROR.Println("Failed to create thumbnail:", err) continue } // If the EXIF said to, rotate the thumbnail. // TODO: maintain the EXIF in the thumb instead. if orientation != 1 { if angleRadians, ok := ORIENTATION_ANGLES[orientation]; ok { rotatedThumbnail := image.NewRGBA(image.Rect(0, 0, 256, 256)) err = graphics.Rotate(rotatedThumbnail, thumbnail, &graphics.RotateOptions{Angle: angleRadians}) if err != nil { rev.ERROR.Println("Failed to rotate:", err) } else { thumbnail = rotatedThumbnail } } } thumbnailFile, err := os.Create(path.Join(thumbDir, photoName)) if err != nil { c.FlashParams() c.Flash.Error("Error creating file:", err) return c.Redirect(Application.Upload) } err = jpeg.Encode(thumbnailFile, thumbnail, nil) if err != nil { c.FlashParams() c.Flash.Error("Failed to save thumbnail:", err) return c.Redirect(Application.Upload) } // Save the photo output, err := os.Create(path.Join(photoDir, photoName)) if err != nil { c.FlashParams() c.Flash.Error("Error creating file:", err) return c.Redirect(Application.Upload) } _, err = io.Copy(output, bytes.NewReader(photoBytes)) output.Close() if err != nil { c.FlashParams() c.Flash.Error("Error writing photo:", err) return c.Redirect(Application.Upload) } var taken time.Time if takenTag, err := x.Get("DateTimeOriginal"); err == nil { taken, err = time.Parse("2006:01:02 15:04:05", takenTag.StringVal()) if err != nil { rev.ERROR.Println("Failed to parse time:", takenTag.StringVal(), ":", err) } } // Save a record of the photo to our database. rect := photoImage.Bounds() photo := models.Photo{ Username: name, Format: format, Name: photoName, Width: rect.Max.X - rect.Min.X, Height: rect.Max.Y - rect.Min.Y, Uploaded: time.Now(), Taken: taken, } c.Txn.Insert(&photo) } c.Flash.Success("%d photos uploaded.", len(photos)) return c.Redirect(Application.View) }
func do(c appengine.Context, key string) (*bytes.Buffer, error) { client := urlfetch.Client(c) resp, err := client.Get(key) if err != nil { return nil, err } defer resp.Body.Close() c.Infof("HTTP GET returned status %v", resp.Status) img, _, err := image.Decode(resp.Body) if err != nil { return nil, err } bnds := img.Bounds() if bnds.Dx() > 1024 { c.Infof("Resizing image", bnds.Dx()) img = resize.Resize(1024, 0, img, resize.Lanczos3) } faces, err := findFaces(c, &img) // todo: should I pass back by reference? if err != nil { return nil, err } bnds = img.Bounds() m := image.NewRGBA(image.Rect(0, 0, bnds.Dx(), bnds.Dy())) draw.Draw(m, bnds, img, image.Point{0, 0}, draw.Src) brd, err := getBeardCached(c) if err != nil { return nil, err } for _, face := range faces { brd_resized := resize.Resize(uint(face.Rectangle.Width*2), 0, brd, resize.Lanczos3) brd_bnds := brd_resized.Bounds() vert := (face.Landmarks.MouthLeft.Y+face.Landmarks.MouthRight.Y)/2 - float32(brd_bnds.Dy())*0.5 rb := image.NewRGBA(image.Rect(0, 0, brd_bnds.Dx(), brd_bnds.Dy())) rad := float64(face.Attributes.Pose.Roll) * math.Pi / 180 graphics.Rotate(rb, brd_resized, &graphics.RotateOptions{rad}) mid := face.Rectangle.Left + face.Rectangle.Width/2 lt := mid - (float32(brd_bnds.Dx()) / 2) sr := image.Rect(0, 0, brd_bnds.Dx()*4, brd_bnds.Dy()*4) dp := image.Point{int(float64(lt)), int(float64(vert))} rt := image.Rectangle{dp, dp.Add(sr.Size())} draw.Draw(m, rt, rb, sr.Min, draw.Over) } img_out := image.Image(m) buffer := new(bytes.Buffer) if err := jpeg.Encode(buffer, img_out, nil); err != nil { return nil, err } return buffer, nil }