HarmonyOS NEXT AI基础视觉服务-背景替换

案例描述

这是一个基于AI基础视觉服务实现的背景替换案例,通过调用设备相册选择图片后对主体进行智能分割,并支持动态更换背景颜色。

实现步骤:

1. 模块导入与组件定义

import { photoAccessHelper } from **********'
import { fileIo } from **********'
import image from **********'
import { subjectSegmentation } from **********'
import { promptAction } from **********'

@Entry
@ComponentV2
struct SubjectSegmentation {
  @Local chooseImage?: PixelMap  // 原始图片
  @Local segmentedImage?: PixelMap // 分割后图片
  @Local bgColor: ResourceColor = Color.White // 背景色状态

2. 图片选择与处理

async segmentImage() {
  if (canIUse('SystemCapability.AI.Vision.SubjectSegmentation')) {
    // 创建图片选择器
    const photoPicker: photoAccessHelper.PhotoViewPicker = new photoAccessHelper.PhotoViewPicker();
    
    // 选择单张图片
    const photoResult = await photoPicker.select({
      MIMEType: photoAccessHelper.PhotoViewMIMETypes.IMAGE_TYPE,
      maxSelectNumber: 1
    })
    
    // 获取图片URI并转换为PixelMap格式
    const photoUri = photoResult.photoUris[0]
    const fileSource = await fileIo.open(photoUri, fileIo.OpenMode.READ_ONLY);
    const imageSource = image.createImageSource(fileSource.fd);
    this.chooseImage = await imageSource.createPixelMap();

3. 主题分割处理

    // 配置视觉识别参数
    const visionInfo: subjectSegmentation.VisionInfo = {
      pixelMap: this.chooseImage,
    };
    
    try {
      // 执行主体分割
      const result = await subjectSegmentation.doSegmentation(visionInfo, {
        enableSubjectForegroundImage: true
      })
      this.segmentedImage = result.fullSubject.foregroundImage
    } catch (e) {
      promptAction.showToast({ message: e.message })
    }
  }
}

4. 背景替换机制

  build() {
    Column({ space: 20 }) {
      // 原始图片展示区域
      Text('原图:')
      Image(this.chooseImage)
        .objectFit(ImageFit.Fill)
        .height('30%')
      
      // 分割后图片展示区域
      Text('扣除背景:')
      Image(this.segmentedImage)
        .objectFit(ImageFit.Fill)
        .height('30%')
        .backgroundColor(this.bgColor)
      
      // 功能操作按钮
      Button('选择图片').onClick(() => this.segmentImage())
      Button('更换背景').onClick(() => {
        // 生成随机RGB背景色
        const a = Math.round(Math.random() * 255)
        const b = Math.round(Math.random() * 255)
        const c = Math.round(Math.random() * 255)
        this.bgColor = `rgb(${a},${b},${c})`
      })
    }
    .padding(15)
    .height('100%')
    .width('100%')
  }
}

总结梳理:

核心点

  1. 多媒体库调用实现图片选择与格式转换
  2. subjectSegmentation.doSegmentation接口完成智能主体分割
  3. 动态背景色机制通过随机RGB值实现

完整代码

// 此处完整保留用户提供的原始代码
import { photoAccessHelper } from **********'
import { fileIo } from **********'
import image from **********'
import { subjectSegmentation } from **********'
import { promptAction } from **********'

@Entry
@ComponentV2
struct SubjectSegmentation {
  @Local chooseImage?: PixelMap
  @Local segmentedImage?: PixelMap
  @Local bgColor: ResourceColor = Color.White

  async segmentImage() {
    if (canIUse('SystemCapability.AI.Vision.SubjectSegmentation')) {
      const photoPicker: photoAccessHelper.PhotoViewPicker = new photoAccessHelper.PhotoViewPicker();
      const photoResult = await photoPicker.select({
        MIMEType: photoAccessHelper.PhotoViewMIMETypes.IMAGE_TYPE,
        maxSelectNumber: 1
      })
      const photoUri = photoResult.photoUris[0]
      const fileSource = await fileIo.open(photoUri, fileIo.OpenMode.READ_ONLY);
      const imageSource = image.createImageSource(fileSource.fd);
      this.chooseImage = await imageSource.createPixelMap();
      const visionInfo: subjectSegmentation.VisionInfo = {
        pixelMap: this.chooseImage,
      };
      try {
        const result = await subjectSegmentation.doSegmentation(visionInfo, {
          enableSubjectForegroundImage: true
        })
        this.segmentedImage = result.fullSubject.foregroundImage
      } catch (e) {
        promptAction.showToast({ message: e.message })
      }
    }
  }

  build() {
    Column({ space: 20 }) {
      Text('原图:')
      Image(this.chooseImage)
        .objectFit(ImageFit.Fill)
        .height('30%')
      Text('扣除背景:')
      Image(this.segmentedImage)
        .objectFit(ImageFit.Fill)
        .height('30%')
        .backgroundColor(this.bgColor)
      Button('选择图片')
        .onClick(() => this.segmentImage())
      Button('更换背景')
        .onClick(() => {
          const a = Math.round(Math.random() * 255)
          const b = Math.round(Math.random() * 255)
          const c = Math.round(Math.random() * 255)
          this.bgColor = `rgb(${a},${b},${c})`
        })
    }
    .padding(15)
    .height('100%')
    .width('100%')
  }
}

全部评论

相关推荐

所谓毕业,就是用痛苦的找工作的过程换一个更痛苦的上班的结局至今都无法理解有人居然能早九晚九坚持下来,更离谱的是还有不少行业,不少岗位比早九晚九强度还要大难以想象965按时下班都能彻底掏空我,然而目前我司还做不到965,并且还在越来越卷中。。。。过了实习期以后更是要多留一会儿签完三方到实习入职的这段时间应该是最爽的那时候没日没夜打游戏,从早打到晚,市面上比较出名的3A基本玩了个遍顺带推推galgame上班以后全没了那些下班晚的,九十点钟的自不必说,回到家收拾收拾,可能都10点多了,打个集贸游戏我倒是勉勉强强还能打1小时,打完快9点,但是上班已经累一天了,打1小时感觉也是身体极限了,坐着也累如果是打2小时打到10点钟,那估计是特别吸引我的游戏前段日子在打三国无双起源,这个可以五一周末也基本都是打游戏,报复性打因为我上班就是为了买外设打游戏不比那些进了大厂的更有人生目标,我是no game no live的人即便我的水平已经菜成一坨了,但是你让我空余时间提升自己也基本不太可能我上班就是为了打游戏,结果你让我为了上班牺牲打游戏的时间,这不是舍本逐末吗深圳这边城市我也不适应,一直在下雨,热,闷,还有街道规划的跟🐶💩一样哪怕窄的只能两个人并排走的路,依然有着来来往往的电瓶车是来来往往哦,要把你身后的和对面逆行的都算上早晚一天要被创飞很难想象这就是一线然后房租还死贵,整租算上物业费一个月都奔着5k去了。。。。很痛苦,感觉这城市哪哪都不适应以前在杭州读书的时候,没喜欢过杭州 觉得不过尔尔现在却是无比怀念了,感觉哪里都不过尔尔的地方,现在看起来跟天堂一样当时只道是寻常一个人躲在阴暗的出租屋,陌生的城市没朋友,没认识的人,更别提只有在二次元的女朋友了这就是毕业的代价,有时候我也在想值不值虽然工作时间比起互联网大厂可能没那么长,但是也没差太多但是也基本没什么时间打游戏和二次元同事那都是一堆奔三的,完全没得聊说回毕业,垃圾学校现在还因为二课学分不够卡我毕业呢,趁着最后的ddl传了几个文件上去不知道能不能过学校真是我大学四年最大的拦路虎马上又要去上班了,上班给人带来了什么呢我最初找工作的目的就是,找个钱多一点的,配一点好的设备打游戏现在我的工资减去吃住玩,可能两三个月就能实现了所以我也迷茫,也没什么动力,感觉现在完全是在拿寿命换钱但是不工作家里也养不起,毕竟我要是家境好又何必干这一行呢上班给我带来的,可能就是一起床就开始emo吧很难想象才放了一个五一,上一天班我都感觉已经一个月没休息了一样然后今天还周三想死。。。。
KaidenLee:既然你知道目前是死循环,那不如周末和假期尝试出去找线下二次元组织社交,或者干脆出去运动,找出打破死循环的突破口。社交、阳光和运动是天然的强效抗抑郁剂。既然改变不了深圳道路交通、工作环境和房租,那不如试试从自我改变开始呢?反正没坏处。
点赞 评论 收藏
分享
评论
点赞
收藏
分享

创作者周榜

更多
牛客网
牛客企业服务